Apa perbedaan antara definisi dan deklarasi?

858

Arti dari keduanya menghindari saya.

Maciek
sumber
91
@Lasse: tidak benar. Sebuah definisi mendefinisikan dan mendeklarasikan ;-)
Steve Jessop
13
Terus terang, saya punya banyak kesulitan belajar yang mana, jadi saya tidak menemukan nama yang jelas. Saya tidak punya masalah dengan maknanya, hanya nama mana yang dikaitkan dengan maknanya.
David Thornley
6
Namun, ini bukan pertanyaan duplikat, karena ini menanyakan tentang C / C ++, sedangkan pertanyaan lain itu menanyakan semua bahasa, atau tidak ada, secara umum. Itu hanya memiliki jawaban duplikat (karena dalam pertanyaan lain itu, beberapa jawaban memilih untuk mengabaikan semua bahasa kecuali C dan / atau C ++).
Steve Jessop
5
@ Davidvidhorn Saya menggunakan trik ini: definisi memberikan deskripsi yang lebih baik dari variabel atau fungsi yang diberikan. Untuk mengingat ini, saya ingat bahwa kata tengah "definisi" memiliki kemiripan dengan kata "lebih halus". :)
Marco Leogrande
4
Hebat berapa banyak omong kosong yang ada di pertanyaan ini. Hanya untuk menunjukkan seberapa banyak bahasa ini disalahpahami, dan bagaimana kesalahpahaman itu disebarkan secara rutin . Sangat menyedihkan, sungguh.
Lightness Races dalam Orbit

Jawaban:

858

Sebuah deklarasi memperkenalkan sebuah identifier dan menjelaskan jenisnya, baik itu jenis, objek, atau fungsi. Deklarasi adalah apa yang dibutuhkan kompiler untuk menerima referensi ke pengidentifikasi itu. Ini adalah deklarasi:

extern int bar;
extern int g(int, int);
double f(int, double); // extern can be omitted for function declarations
class foo; // no extern allowed for type declarations

Sebuah definisi sebenarnya instantiates / alat pengenal ini. Itulah yang dibutuhkan penghubung untuk menautkan referensi ke entitas tersebut. Ini adalah definisi yang sesuai dengan deklarasi di atas:

int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};

Definisi dapat digunakan sebagai pengganti deklarasi.

Identifier dapat dideklarasikan sesering yang Anda inginkan. Dengan demikian, berikut ini legal di C dan C ++:

double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);

Namun, harus didefinisikan tepat sekali. Jika Anda lupa mendefinisikan sesuatu yang telah dideklarasikan dan dirujuk di suatu tempat, maka linker tidak tahu harus menautkan referensi apa dan mengeluh tentang simbol yang hilang. Jika anda mendefinisikan sesuatu yang lebih dari sekali, maka linker tidak tahu mana dari definisi-link referensi ke dan mengeluh tentang simbol digandakan.


Karena debat apa yang merupakan deklarasi kelas vs definisi kelas dalam C ++ terus muncul (dalam jawaban dan komentar untuk pertanyaan lain), saya akan menempelkan kutipan dari standar C ++ di sini.
Pada 3.1 / 2, C ++ 03 mengatakan:

Deklarasi adalah definisi kecuali [[]] adalah deklarasi nama kelas [...].

3.1 / 3 kemudian memberikan beberapa contoh. Di antara mereka:

[Contoh: [...]
struct S {int a; int b; }; // mendefinisikan S, S :: a, dan S :: b [...]
struct S; // menyatakan S
—Kirim contoh

Untuk jumlah itu: The C ++ standar menganggap struct x;menjadi deklarasi dan struct x {};sebuah definisi . (Dengan kata lain, "peneruskan deklarasi" keliru , karena tidak ada bentuk lain dari deklarasi kelas di C ++.)

Terima kasih kepada litb (Johannes Schaub) yang menggali pasal dan ayat yang sebenarnya dalam salah satu jawabannya.

sbi
sumber
2
@unknown: kompiler Anda rusak karena Anda salah menyalin kode sbi. Misalnya, 6.7.2 (2) dalam N1124: "Semua deklarasi yang merujuk ke objek atau fungsi yang sama harus memiliki tipe yang kompatibel; jika tidak, perilaku tidak terdefinisi."
Steve Jessop
4
@Brian: "extern int i;" mengatakan bahwa saya adalah seorang int di suatu tempat, jangan khawatir tentang hal itu. "int i;" berarti saya adalah int, dan alamat serta ruang lingkupnya ditentukan di sini.
David Thornley
12
@ Brian: Anda salah. extern int iadalah deklarasi, karena hanya memperkenalkan / menetapkan i. Anda dapat memiliki banyak extern int idi setiap unit kompilasi yang Anda inginkan. int iNamun, adalah definisi. Ini menunjukkan ruang untuk integer berada di unit terjemahan ini dan menyarankan linker untuk menautkan semua referensi iterhadap entitas ini. Jika Anda memiliki lebih atau kurang dari salah satu definisi ini, penghubung akan mengeluh.
sbi
4
@Brian int i;dalam ruang lingkup file / global atau fungsi adalah definisi baik dalam C dan C ++. Dalam C karena mengalokasikan penyimpanan, dan dalam C ++ karena tidak memiliki penentu eksternal atau spesifikasi-tautan. Ini sama dengan hal yang sama, yang dikatakan sbi: dalam kedua kasus deklarasi ini menentukan objek yang semua rujukannya ke "i" dalam lingkup itu harus dihubungkan.
Steve Jessop
4
@unknown, waspadalah Anda tidak dapat mendeklarasikan ulang anggota di ruang lingkup kelas : struct A { double f(int, double); double f(int, double); };tidak valid, tentu saja. Itu diizinkan di tempat lain. Ada beberapa tempat di mana Anda dapat menyatakan hal, tetapi tidak menentukan, terlalu: void f() { void g(); }valid, tapi tidak berikut: void f() { void g() { } };. Apa definisi dan apa deklarasi memiliki aturan halus ketika datang ke template - berhati-hatilah! +1 untuk jawaban yang bagus.
Johannes Schaub - litb
168

Dari bagian standar C ++ 3.1:

Sebuah deklarasi memperkenalkan nama menjadi unit terjemahan atau redeclares nama diperkenalkan oleh deklarasi sebelumnya. Deklarasi menentukan interpretasi dan atribut dari nama-nama ini.

Paragraf berikutnya menyatakan (penekanan saya) bahwa deklarasi adalah definisi kecuali ...

... itu mendeklarasikan suatu fungsi tanpa menentukan tubuh fungsi:

void sqrt(double);  // declares sqrt

... itu menyatakan anggota statis dalam definisi kelas:

struct X
{
    int a;         // defines a
    static int b;  // declares b
};

... itu menyatakan nama kelas:

class Y;

... itu berisi extern kata kunci tanpa inisialisasi atau badan fungsi:

extern const int i = 0;  // defines i
extern int j;  // declares j
extern "C"
{
    void foo();  // declares foo
}

... atau a typedefatauusing pernyataan.

typedef long LONG_32;  // declares LONG_32
using namespace std;   // declares std

Sekarang untuk alasan besar mengapa penting untuk memahami perbedaan antara deklarasi dan definisi: the Aturan Satu Definisi . Dari bagian 3.2.1 dari standar C ++:

Tidak ada unit terjemahan yang memuat lebih dari satu definisi variabel, fungsi, tipe kelas, tipe enumerasi, atau templat.

Michael Kristofik
sumber
"mendeklarasikan anggota statis dalam definisi kelas" - Ini benar bahkan jika anggota statis diinisialisasi, benar? Bisakah kita memberi contoh struct x {static int b = 3; };?
RJFalconer
@RJFalconer Anda benar; inisialisasi tidak serta - merta mengubah deklarasi menjadi definisi (bertentangan dengan apa yang diharapkan; tentu saja saya menganggap ini mengejutkan). Modifikasi Anda pada contoh ini sebenarnya ilegal kecuali bdinyatakan juga const. Lihat stackoverflow.com/a/3536513/1858225 dan daniweb.com/software-development/cpp/threads/140739/… .
Kyle Strand
1
Ini menarik bagi saya. Menurut jawaban Anda, tampaknya dalam C ++, deklarasi juga merupakan definisi (dengan pengecualian), sedangkan dalam standar C itu diutarakan dari perspektif lain (C99, bagian 6.7, Deklarasi): " Definisi pengidentifikasi adalah deklarasi untuk pengidentifikasi itu bahwa: [diikuti oleh kriteria untuk kasus yang berbeda] ". Berbagai cara untuk melihatnya, kurasa. :)
Victor Zamanian
Deklarasi adalah untuk kompiler untuk menerima nama (untuk memberi tahu kompiler bahwa nama itu legal, nama tersebut diperkenalkan dengan maksud bukan salah ketik). Definisi adalah tempat nama dan isinya dikaitkan. Definisi tersebut digunakan oleh penghubung untuk menautkan referensi nama ke konten nama.
Gab 是 好人
137

Deklarasi: "Di suatu tempat, ada foo."

Definisi: "... dan ini dia!"

alas tiang
sumber
3
Deklarasi adalah untuk kompiler untuk menerima nama (untuk memberi tahu kompiler bahwa nama itu legal, nama tersebut diperkenalkan dengan maksud bukan salah ketik). Definisi adalah tempat nama dan isinya dikaitkan. Definisi tersebut digunakan oleh penghubung untuk menautkan referensi nama ke konten nama.
Gab 是 好人
46

Ada kasus tepi yang menarik di C ++ (beberapa di antaranya di C juga). Mempertimbangkan

T t;

Itu bisa berupa definisi atau deklarasi, tergantung pada jenisnya T:

typedef void T();
T t; // declaration of function "t"

struct X { 
  T t; // declaration of function "t".
};

typedef int T;
T t; // definition of object "t".

Di C ++, saat menggunakan templat, ada kasing lain.

template <typename T>
struct X { 
  static int member; // declaration
};

template<typename T>
int X<T>::member; // definition

template<>
int X<bool>::member; // declaration!

Deklarasi terakhir bukan definisi. Ini adalah deklarasi spesialisasi eksplisit dari anggota statis X<bool>. Ia memberi tahu kompiler: "Jika menyangkut instantiasi X<bool>::member, maka jangan instantiasi definisi anggota dari templat utama, tetapi gunakan definisi yang ditemukan di tempat lain". Untuk menjadikannya definisi, Anda harus menyediakan inisialisasi

template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
Johannes Schaub - litb
sumber
35

Pernyataan

Deklarasi memberitahu kompiler bahwa elemen atau nama program ada. Deklarasi memperkenalkan satu atau lebih nama ke dalam suatu program. Deklarasi dapat terjadi lebih dari sekali dalam suatu program. Oleh karena itu, kelas, struktur, tipe enumerasi, dan tipe yang ditentukan pengguna lainnya dapat dideklarasikan untuk setiap unit kompilasi.

Definisi

Definisi menentukan kode atau data apa yang diuraikan namanya. Sebuah nama harus dideklarasikan sebelum dapat digunakan.

adatapost
sumber
Um, bukankah Anda bahkan dapat mendefinisikan kelas dan enum di setiap unit kompilasi? Setidaknya saya memasukkan definisi kelas ke dalam header saya dan memasukkan semuanya ke seluruh. Eh, class foo {}; apakah definisi kelas , bukan?
sbi
1
Iya. Namun, "kelas foo;" adalah deklarasi. Ini memberitahu kompiler bahwa foo adalah kelas. "class foo {};" adalah sebuah definisi. Ini memberitahu kompiler persis apa kelas foo.
David Thornley
1
Pengecualian adalah nama anggota kelas yang dapat digunakan sebelum dideklarasikan.
Johannes Schaub - litb
1
Ya, itulah yang saya maksud. Jadi Anda dapat melakukan hal berikut: struct foo {void b () {f (); } membatalkan f (); }, f terlihat meskipun belum dideklarasikan. Berikut ini juga berfungsi: struct foo {void b (int = bar ()); ketikkan bar int; } ;. Itu terlihat sebelum deklarasi di "semua badan fungsi, argumen default, konstruktor ctor-initializers". Bukan dalam tipe pengembalian :(
Johannes Schaub - litb
1
@ litb: Tidak terlihat sebelum deklarasi, hanya saja penggunaan pengenal dipindahkan di belakang deklarasi. Ya, saya tahu, efeknya sama untuk banyak kasus. Tetapi tidak untuk semua kasus, itulah mengapa saya pikir kita harus menggunakan penjelasan yang tepat. - Ups, tunggu. Itu terlihat dalam argumen default? Nah, itu pasti mendatangkan malapetaka dengan pemahaman saya. Sialan! <pouts>
sbi
22

Dari standar C99, 6.7 (5):

Deklarasi menentukan interpretasi dan atribut dari set pengidentifikasi. Sebuah definisi dari sebuah identifier adalah deklarasi identifier bahwa:

  • untuk suatu objek, menyebabkan penyimpanan dicadangkan untuk objek itu;
  • untuk suatu fungsi, termasuk fungsi tubuh;
  • untuk konstanta enumerasi atau nama typedef, adalah (hanya) deklarasi pengidentifikasi.

Dari standar C ++, 3.1 (2):

Deklarasi adalah definisi kecuali jika ia mendeklarasikan suatu fungsi tanpa menentukan tubuh fungsi, itu berisi penspesifikasi eksternal atau suatu keterkaitan-spesifikasi dan bukan suatu penginisialisasi atau suatu badan fungsi, ia mendeklarasikan anggota data statis dalam suatu deklarasi kelas, itu adalah suatu deklarasi nama kelas, atau itu adalah deklarasi typedef, deklarasi use, atau directive use.

Lalu ada beberapa contoh.

Sangat menarik (atau tidak, tapi saya sedikit terkejut olehnya), typedef int myint;adalah definisi dalam C99, tetapi hanya deklarasi di C ++.

Steve Jessop
sumber
@onebyone: Mengenai typedef, bukankah itu berarti bisa diulang dalam C ++, tetapi tidak di C99?
sbi
Itulah yang mengejutkan saya, dan sejauh menyangkut satu unit terjemahan, ya ada perbedaan itu. Tetapi jelas typedef dapat diulang dalam C99 dalam unit terjemahan yang berbeda. C tidak memiliki "aturan satu definisi" yang eksplisit seperti C ++, jadi aturan yang dimilikinya mengizinkannya. C ++ memilih untuk mengubahnya ke deklarasi, tetapi juga aturan satu definisi mencantumkan hal-hal apa yang berlaku, dan typedef bukan salah satunya. Jadi pengulangan akan diizinkan dalam C ++ di bawah ODR seperti yang diucapkan, bahkan jika typedef adalah definisi. Tampaknya tidak perlu pilih-pilih.
Steve Jessop
... tapi saya rasa daftar di ODR sebenarnya mencantumkan semua hal yang mungkin untuk memiliki definisi. Jika demikian, maka daftar itu sebenarnya berlebihan, dan hanya ada untuk membantu.
Steve Jessop
Apa definisi ODR std tentang definisi kelas? Mereka harus diulang.
sbi
2
@sbi: ODR mengatakan "(1) Tidak ada unit terjemahan yang harus mengandung lebih dari satu definisi dari ... jenis kelas" dan "(5) Mungkin ada lebih dari satu definisi dari jenis kelas ... dalam program asalkan setiap definisi muncul di unit terjemahan yang berbeda "dan kemudian beberapa persyaratan tambahan yang berarti" definisi adalah sama ".
Steve Jessop
17

Dari wiki.answers.com:

Istilah deklarasi berarti (dalam C) bahwa Anda memberi tahu kompiler tentang jenis, ukuran dan dalam hal deklarasi fungsi, jenis dan ukuran parameternya dari variabel apa pun, atau tipe atau fungsi yang ditentukan pengguna dalam program Anda. Tidak ada ruang yang disimpan dalam memori untuk variabel apa pun dalam hal deklarasi. Namun kompiler tahu berapa banyak ruang untuk cadangan jika variabel jenis ini dibuat.

misalnya, berikut ini semua deklarasi:

extern int a; 
struct _tagExample { int a; int b; }; 
int myFunc (int a, int b);

Definisi di sisi lain berarti bahwa selain semua hal yang dilakukan deklarasi, ruang juga dicadangkan dalam memori. Anda dapat mengatakan "DEFINISI = DEKLARASI + PEMESANAN RUANG" berikut ini adalah contoh definisi:

int a; 
int b = 0; 
int myFunc (int a, int b) { return a + b; } 
struct _tagExample example; 

lihat Jawaban .

Marcin Gil
sumber
3
Ini juga salah (walaupun jauh lebih dekat dari yang lain): struct foo {};adalah definisi , bukan deklarasi. Deklarasi fooakan menjadi struct foo;. Dari itu, kompiler tidak tahu berapa banyak ruang untuk memesan fooobjek.
sbi
1
@ Marsin: sbi mengatakan bahwa "kompiler tahu berapa banyak ruang untuk cadangan jika variabel jenis ini dibuat" tidak selalu benar. struct foo;adalah deklarasi, tetapi ia tidak memberi tahu kompiler ukuran foo. Saya akan menambahkan itu struct _tagExample { int a; int b; };adalah definisi. Jadi dalam konteks ini menyesatkan menyebutnya deklarasi. Tentu saja itu satu, karena semua definisi adalah deklarasi, tetapi Anda tampaknya menyarankan bahwa itu bukan definisi. Ini adalah definisi, dari _tagExample.
Steve Jessop
1
@Marcin Gil: Yang berarti bahwa wiki "Jawaban" tidak selalu akurat. Saya harus downvote untuk informasi yang salah di sini.
David Thornley
1
Kita belajar bahwa apa yang dikutip adatapost itu benar tetapi tidak (IMO) benar-benar menjawab pertanyaan itu. Apa yang dikutip Marcin salah. Mengutip standar adalah benar dan menjawab pertanyaan, tetapi sangat sulit untuk dibuat menjadi kepala atau ekor.
Steve Jessop
1
@ David Thornley - tidak masalah :) Ini adalah tentang apa situs ini. Kami memilih dan memverifikasi info.
Marcin Gil
13

Pembaruan C ++ 11

Karena saya tidak melihat jawaban yang berkaitan dengan C ++ 11 di sini adalah satu.

Deklarasi adalah definisi kecuali jika mendeklarasikan a / n:

  • opum enum - enum X : int;
  • parameter template - T intemplate<typename T> class MyArray;
  • deklarasi parameter - x dan y inint add(int x, int y);
  • deklarasi alias - using IntVector = std::vector<int>;
  • deklarasi penegasan statis - static_assert(sizeof(int) == 4, "Yikes!")
  • deklarasi atribut (implementasi-didefinisikan)
  • deklarasi kosong ;

Klausa tambahan yang diwarisi dari C ++ 03 oleh daftar di atas:

  • deklarasi fungsi - tambahkan diint add(int x, int y);
  • extern specifier yang berisi deklarasi atau specifier tautan - extern int a; atauextern "C" { ... };
  • anggota data statis di kelas - x inclass C { static int x; };
  • deklarasi kelas / struct - struct Point;
  • deklarasi typedef - typedef int Int;
  • menggunakan deklarasi - using std::cout;
  • menggunakan arahan - using namespace NS;

Deklarasi templat adalah deklarasi. Deklarasi templat juga merupakan definisi jika deklarasi mendefinisikan fungsi, kelas, atau anggota data statis.

Contoh dari standar yang membedakan antara deklarasi dan definisi yang menurut saya sangat membantu dalam memahami nuansa di antara mereka:

// except one all these are definitions
int a;                                  // defines a
extern const int c = 1;                 // defines c
int f(int x) { return x + a; }          // defines f and defines x
struct S { int a; int b; };             // defines S, S::a, and S::b
struct X {                              // defines X
    int x;                              // defines non-static data member x
    static int y;                       // DECLARES static data member y
    X(): x(0) { }                       // defines a constructor of X
};
int X::y = 1;                           // defines X::y
enum { up , down };                     // defines up and down
namespace N { int d; }                  // defines N and N::d
namespace N1 = N;                       // defines N1
X anX;                                  // defines anX


// all these are declarations
extern int a;                           // declares a
extern const int c;                     // declares c
int f(int);                             // declares f
struct S;                               // declares S
typedef int Int;                        // declares Int
extern X anotherX;                      // declares anotherX
using N::d;                             // declares N::d


// specific to C++11 - these are not from the standard
enum X : int;                           // declares X with int as the underlying type
using IntVector = std::vector<int>;     // declares IntVector as an alias to std::vector<int>
static_assert(X::y == 1, "Oops!");      // declares a static_assert which can render the program ill-formed or have no effect like an empty declaration, depending on the result of expr
template <class T> class C;             // declares template class C
;                                       // declares nothing
legends2k
sumber
6

Definisi:

extern int a;      // Declaration 
int a;             // Definition
a = 10             // Initialization
int b = 10;        // Definition & Initialization

Definisi mengaitkan variabel dengan tipe dan mengalokasikan memori, sedangkan deklarasi hanya menentukan tipe tetapi tidak mengalokasikan memori. Deklarasi lebih berguna ketika Anda ingin merujuk variabel sebelum definisi.

* Jangan bingung definisi dengan inisialisasi. Keduanya berbeda, inisialisasi memberikan nilai pada variabel. Lihat contoh di atas.

Berikut ini adalah beberapa contoh definisi.

int a;
float b;
double c;

Sekarang deklarasi fungsi:

int fun(int a,int b); 

Catat titik koma di akhir fungsi jadi dikatakan hanya deklarasi. Compiler tahu bahwa di suatu tempat di program, fungsi itu akan didefinisikan dengan prototipe itu. Sekarang jika kompiler mendapat panggilan fungsi sesuatu seperti ini

int b=fun(x,y,z);

Compiler akan melempar kesalahan yang mengatakan bahwa tidak ada fungsi seperti itu. Karena tidak memiliki prototipe untuk fungsi itu.

Perhatikan perbedaan antara dua program.

Program 1

#include <stdio.h>
void print(int a)
{
     printf("%d",a);
}
main()
{
    print(5);
}

Dalam hal ini, fungsi cetak dideklarasikan dan didefinisikan juga. Karena panggilan fungsi datang setelah definisi. Sekarang lihat program selanjutnya.

Program 2

 #include <stdio.h>
 void print(int a); // In this case this is essential
 main()
 {
    print(5);
 }
 void print(int a)
 {
     printf("%d",a);
 }

Ini penting karena pemanggilan fungsi mendahului definisi sehingga kompiler harus tahu apakah ada fungsi tersebut. Jadi kami mendeklarasikan fungsi yang akan menginformasikan kompiler.

Definisi:

Bagian dari pendefinisian fungsi ini disebut Definisi. Ia mengatakan apa yang harus dilakukan di dalam fungsi.

void print(int a)
{
    printf("%d",a);
}
SRIDHARAN
sumber
2
int a; //declaration; a=10; //definitionIni sepenuhnya salah. Ketika berbicara tentang objek durasi penyimpanan otomatis (objek dideklarasikan di dalam definisi fungsi yang tidak dideklarasikan dengan specifier kelas penyimpanan lain seperti extern) ini selalu definisi.
Joey Pabalinas
Perbedaan utama untuk dipahami adalah bahwa deklarasi mengatakan "sesuatu ada di suatu tempat yang memiliki sifat-sifat ini (ketik dll)," sedangkan definisi mengatakan "Saya mendeklarasikan sesuatu dengan sifat-sifat ini, dan saya juga instantiasi di sini sebagai baik." Karena Anda tidak dapat meneruskan mendeklarasikan objek durasi penyimpanan otomatis seperti itu, mereka akan selalu menjadi definisi.
Joey Pabalinas
Kecuali mungkin beberapa kasus sudut typedef aneh yang selalu saya lupakan, aturan praktisnya adalah bahwa semua definisi adalah deklarasi. Pikirkan tentang itu; ketika Anda membuat instance sesuatu, Anda juga perlu memberi tahu kompiler bahwa benda itu ada dan apa sifatnya yang benar?
Joey Pabalinas
Memperbarui jawabannya sesuai komentar pertama Anda. namun saya tidak setuju dengan komentar ini "ketika Anda membuat instance sesuatu, Anda juga perlu memberi tahu kompiler bahwa hal itu ada". Kami tidak selalu menentukan jenis lhs saat membuat instance. Mis: a = 10. Kami tidak menentukan "sifat" apa pun di sini.
SRIDHARAN
4

definisi berarti fungsi aktual ditulis & deklarasi berarti fungsi mendeklarasikan sederhana untuk misalnya

void  myfunction(); //this is simple declaration

dan

void myfunction()
{
 some statement;    
}

ini adalah definisi fungsi fungsi

Flexo
sumber
1
Dan bagaimana dengan tipe dan objek?
sbi
4

Aturan praktis:

  • Sebuah deklarasi memberitahu compiler bagaimana menafsirkan data variabel di memori. Ini diperlukan untuk setiap akses.

  • Sebuah definisi cadangan memori untuk membuat variabel yang ada. Ini harus terjadi tepat satu kali sebelum akses pertama.

bjhend
sumber
2
Ini hanya berlaku untuk objek. Bagaimana dengan tipe dan fungsi?
Lightness Races dalam Orbit
4

Untuk memahami kata benda, mari kita fokus pada kata kerja terlebih dahulu.

menyatakan - untuk mengumumkan secara resmi; menyatakan

define - untuk menampilkan atau menggambarkan (seseorang atau sesuatu) dengan jelas dan lengkap

Jadi, ketika Anda mendeklarasikan sesuatu, Anda hanya mengatakan apa itu .

// declaration
int sum(int, int);

Baris ini mendeklarasikan fungsi C yang dipanggil sumyang mengambil dua argumen tipe intdan mengembalikan sebuah int. Namun, Anda belum dapat menggunakannya.

Ketika Anda memberikan cara kerjanya sebenarnya , itulah definisi untuk itu.

// definition
int sum(int x, int y)
{
    return x + y;
}
Karoly Nyisztor
sumber
3

Untuk memahami perbedaan antara deklarasi dan definisi, kita perlu melihat kode assembly:

uint8_t   ui8 = 5;  |   movb    $0x5,-0x45(%rbp)
int         i = 5;  |   movl    $0x5,-0x3c(%rbp)
uint32_t ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
uint64_t ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
double   doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
                        movsd   %xmm0,-0x8(%rbp)

dan ini hanya definisi:

ui8 = 5;   |   movb    $0x5,-0x45(%rbp)
i = 5;     |   movl    $0x5,-0x3c(%rbp)
ui32 = 5;  |   movl    $0x5,-0x38(%rbp)
ui64 = 5;  |   movq    $0x5,-0x10(%rbp)
doub = 5;  |   movsd   0x328(%rip),%xmm0        # 0x400a20
               movsd   %xmm0,-0x8(%rbp)

Seperti yang Anda lihat tidak ada yang berubah.

Deklarasi berbeda dari definisi karena memberikan informasi yang hanya digunakan oleh kompiler. Sebagai contoh, uint8_t memberitahu kompiler untuk menggunakan asm function movb.

Lihat itu:

uint def;                  |  no instructions
printf("some stuff...");   |  [...] callq   0x400450 <printf@plt>
def=5;                     |  movb    $0x5,-0x45(%rbp)

Deklarasi tidak memiliki instruksi yang setara karena tidak ada sesuatu yang harus dieksekusi.

Lebih jauh deklarasi memberitahu kompiler lingkup variabel.

Kita dapat mengatakan bahwa deklarasi adalah informasi yang digunakan oleh kompiler untuk menetapkan penggunaan variabel yang benar dan untuk berapa lama sebagian memori dimiliki oleh variabel tertentu.

Pangeran
sumber
2

Tidak bisakah Anda menyatakan dengan syarat yang paling umum, bahwa deklarasi adalah pengidentifikasi di mana tidak ada penyimpanan yang dialokasikan dan definisi sebenarnya mengalokasikan penyimpanan dari pengidentifikasi yang dinyatakan?

Satu pemikiran menarik - templat tidak dapat mengalokasikan penyimpanan sampai kelas atau fungsi dikaitkan dengan informasi jenis. Jadi apakah pengidentifikasi templat merupakan deklarasi atau definisi? Ini harus berupa deklarasi karena tidak ada penyimpanan yang dialokasikan, dan Anda hanya 'membuat prototip' kelas templat atau fungsi.


sumber
1
Definisi Anda tidak salah, tetapi "definisi penyimpanan" selalu tampak canggung ketika datang ke definisi fungsi. Mengenai templat: Ini template<class T> struct foo;adalah deklarasi templat , dan begitu juga ini template<class T> void f();. Definisi template mencerminkan definisi kelas / fungsi dengan cara yang sama. (Perhatikan bahwa nama templat bukan jenis atau nama fungsi . Satu tempat di mana Anda dapat melihat ini adalah ketika Anda tidak dapat meneruskan templat sebagai parameter jenis templat lainnya. Jika Anda ingin meneruskan templat alih-alih jenis, Anda memerlukan parameter templat templat. )
sbi
Setuju bahwa 'definisi penyimpanan' adalah canggung, terutama mengenai definisi fungsi. Deklarasi adalah int foo () dan definisi adalah int foo () {// beberapa kode di sini ..}. Saya biasanya perlu untuk membungkus otak kecil saya dengan konsep Saya kenal - 'penyimpanan' adalah salah satu cara tersebut untuk tetap lurus untuk saya setidaknya ... :)
2

Temukan jawaban serupa di sini: Teknis Pertanyaan Wawancara di C .

Sebuah deklarasi menyediakan nama untuk program; sebuah definisi memberikan deskripsi unik tentang suatu entitas (misalnya tipe, instance, dan fungsi) dalam program. Deklarasi dapat diulang dalam lingkup yang diberikan, itu memperkenalkan nama dalam lingkup yang diberikan.

Deklarasi adalah definisi kecuali:

  • Deklarasi mendeklarasikan fungsi tanpa menentukan tubuhnya,
  • Deklarasi berisi specifier eksternal dan tidak ada inisialisasi atau badan fungsi,
  • Deklarasi adalah deklarasi anggota data kelas statis tanpa definisi kelas,
  • Deklarasi adalah definisi nama kelas,

Definisi adalah deklarasi kecuali:

  • Definisi mendefinisikan anggota data kelas statis,
  • Definisi mendefinisikan fungsi anggota non-inline.
Santosh
sumber
1

Ini kedengarannya benar-benar murahan, tetapi ini adalah cara terbaik saya dapat menjaga istilah-istilah itu tetap di kepala saya:

Deklarasi: Gambar Thomas Jefferson memberikan pidato ... "SAYA SUDAH MENYATAKAN BAHWA FOO INI ADA DI KODE SUMBER INI !!!"

Definisi: gambar sebuah kamus, Anda mencari Foo dan apa artinya sebenarnya.

Sudah
sumber
1

Deklarasi menyajikan nama simbol ke kompiler. Definisi adalah deklarasi yang mengalokasikan ruang untuk simbol.

int f(int x); // function declaration (I know f exists)

int f(int x) { return 2*x; } // declaration and definition
hdante
sumber
1

Menurut manual pustaka GNU C ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )

Dalam C, deklarasi hanya menyediakan informasi bahwa ada fungsi atau variabel dan memberikan tipenya. Untuk deklarasi fungsi, informasi tentang jenis argumennya dapat diberikan juga. Tujuan dari deklarasi adalah untuk memungkinkan kompiler untuk memproses referensi ke variabel dan fungsi yang dideklarasikan dengan benar. Definisi, di sisi lain, sebenarnya mengalokasikan penyimpanan untuk variabel atau mengatakan apa fungsi tidak.

LinuxBabe
sumber
0

Konsep Deklarasi dan Definisi akan membentuk jebakan ketika Anda menggunakan kelas penyimpanan eksternal karena definisi Anda akan berada di beberapa lokasi lain dan Anda mendeklarasikan variabel dalam file kode lokal Anda (halaman). Satu perbedaan antara C dan C ++ adalah bahwa dalam C Anda deklarasi dilakukan secara normal pada awal halaman fungsi atau kode. Dalam C ++ tidak seperti itu. Anda dapat mendeklarasikan di tempat pilihan Anda.

achoora
sumber
1
Ini membingungkan deklarasi dengan definisi dan jelas salah.
sbi
0

Contoh favorit saya adalah "int Num = 5" di sini variabel Anda 1. didefinisikan sebagai int 2. dinyatakan sebagai Num dan 3. instantiated dengan nilai lima. Kita

  • Tentukan jenis objek, yang mungkin built-in atau kelas atau struct.
  • Nyatakan nama suatu objek, jadi segala sesuatu dengan nama telah dideklarasikan yang meliputi Variabel, Fungsi, dll.

Kelas atau struct memungkinkan Anda untuk mengubah bagaimana objek akan didefinisikan ketika nanti digunakan. Sebagai contoh

  • Seseorang dapat mendeklarasikan variabel atau array yang heterogen yang tidak didefinisikan secara spesifik.
  • Menggunakan offset di C ++ Anda dapat mendefinisikan objek yang tidak memiliki nama yang dideklarasikan.

Ketika kita belajar pemrograman, kedua istilah ini sering membingungkan karena kita sering melakukan keduanya secara bersamaan.

Jason K.
sumber
Saya tidak mengerti mengapa begitu banyak orang yang mengangkat jawaban sbi. Saya memilih jawaban bjhend, yang cukup bagus, ringkas, akurat, dan jauh lebih tepat waktu daripada jawaban saya. Saya sedih melihat bahwa saya adalah orang pertama yang melakukannya dalam 4 tahun.
Jason K.
0

Tahapan dari generasi yang dapat dieksekusi:

(1) pra-prosesor -> (2) penerjemah / kompiler -> (3) tautan

Pada tahap 2 (penerjemah / kompiler), pernyataan deklarasi dalam kode kita memberi tahu kompiler bahwa hal-hal ini akan kita gunakan di masa depan dan Anda dapat menemukan definisi nanti, artinya adalah:

penerjemah memastikan bahwa: apa itu apa? berarti deklarasi

dan (3) tahap (penghubung) perlu definisi untuk mengikat hal-hal

Linker memastikan bahwa: di mana ada apa? berarti definisi

Jeet Parikh
sumber
0

Ada beberapa definisi yang sangat jelas ditaburkan di seluruh K&R (edisi ke-2); membantu menempatkan mereka di satu tempat dan membacanya sebagai satu:

"Definisi" mengacu pada tempat di mana variabel dibuat atau ditugaskan penyimpanan; "deklarasi" mengacu pada tempat-tempat di mana sifat variabel dinyatakan tetapi tidak ada penyimpanan yang dialokasikan. [hal. 33]

...

Penting untuk membedakan antara deklarasi variabel eksternal dan definisinya . Deklarasi mengumumkan properti variabel (terutama tipenya); definisi juga menyebabkan penyimpanan dikesampingkan. Jika garis

int sp;
double val[MAXVAL]

muncul di luar fungsi apa pun, mereka menentukan variabel eksternal spdan val, menyebabkan penyimpanan disingkirkan, dan juga berfungsi sebagai deklarasi untuk sisa file sumber itu.

Di sisi lain, garis

extern int sp;
extern double val[];

mendeklarasikan untuk sisa file sumber yang spmerupakan intdan itu valadalah doublearray (yang ukurannya ditentukan di tempat lain), tetapi mereka tidak membuat variabel atau menyimpan cadangan untuk mereka.

Hanya boleh ada satu definisi variabel eksternal di antara semua file yang membentuk program sumber. ... Ukuran array harus ditentukan dengan definisi, tetapi opsional denganextern deklarasi. [hlm. 80-81]

...

Deklarasi menentukan interpretasi yang diberikan kepada masing-masing pengidentifikasi; mereka tidak perlu menyimpan penyimpanan yang terkait dengan pengidentifikasi. Deklarasi bahwa penyimpanan cadangan disebut definisi . [hal. 210]

Brad Solomon
sumber
-1

Deklarasi berarti memberi nama dan jenis ke variabel (dalam hal deklarasi variabel), misalnya:

int i;

atau berikan nama, jenis kembali dan jenis parameter ke fungsi tanpa badan (dalam hal deklarasi fungsi), misalnya:

int max(int, int);

sedangkan definisi berarti memberikan nilai ke variabel (dalam hal definisi variabel), misalnya:

i = 20;

atau menyediakan / menambah isi (fungsi) ke suatu fungsi disebut definisi fungsi, misalnya:

int max(int a, int b)
{
   if(a>b)   return a;
   return b;  
}

banyak deklarasi dan definisi waktu dapat dilakukan bersama sebagai:

int i=20;

dan:

int max(int a, int b)
{
    if(a>b)   return a;
    return b;    
} 

Dalam kasus di atas kami mendefinisikan dan mendeklarasikan variabel idan function max().

Puneet Purohit
sumber
maksud sebenarnya dari definisi jika untuk menetapkan nilai / tubuh ke variabel / fungsi sedangkan deklarasi berarti memberikan nama, ketik ke variabel / fungsi
Puneet Purohit
Anda dapat mendefinisikan sesuatu tanpa memberinya nilai.
Lightness Races in Orbit
1
Sama seperti ini:int x;
Lightness Races di Orbit
ini adalah deklarasi variabel x bukan pembelaannya
Puneet Purohit
2
Tidak, keduanya. Anda membingungkan definisi dengan inisialisasi.
Lightness Races dalam Orbit