Il significato di entrambi mi sfugge.
Il significato di entrambi mi sfugge.
Risposte:
Una dichiarazione introduce un identificatore e ne descrive il tipo, sia esso un tipo, un oggetto o una funzione. Una dichiarazione è ciò di cui il compilatore deve accettare i riferimenti a quell'identificatore. Queste sono dichiarazioni:
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
Una definizione in realtà istanzia / implementa questo identificatore. È ciò di cui il linker ha bisogno per collegare riferimenti a tali entità. Queste sono definizioni corrispondenti alle dichiarazioni di cui sopra:
int bar;
int g(int lhs, int rhs) {return lhs*rhs;}
double f(int i, double d) {return i+d;}
class foo {};
Una definizione può essere utilizzata al posto di una dichiarazione.
Un identificatore può essere dichiarato tutte le volte che vuoi. Pertanto, quanto segue è legale in C e 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);
Tuttavia, deve essere definito esattamente una volta. Se dimentichi di definire qualcosa che è stato dichiarato e referenziato da qualche parte, il linker non sa a cosa collegare i riferimenti e si lamenta di un simbolo mancante. Se definisci qualcosa più di una volta, il linker non sa a quale delle definizioni collegare i riferimenti e si lamenta dei simboli duplicati.
Dal momento che il dibattito su ciò che è una dichiarazione di classe contro una definizione di classe in C ++ continua (nelle risposte e nei commenti ad altre domande), incollerò qui una citazione dallo standard C ++.
A 3.1 / 2, C ++ 03 dice:
Una dichiarazione è una definizione a meno che [...] non sia una dichiarazione di nome di classe [...].
3.1 / 3 fornisce quindi alcuni esempi. Tra questi:
[Esempio: [...] struct S {int a; int b; }; // definisce S, S :: a e S :: b [...] struct S; // dichiara S —Esempio
Per riassumere: lo standard C ++ considera struct x;
una dichiarazione e struct x {};
una definizione . (In altre parole, "dichiarazione in avanti" è un termine improprio , poiché non ci sono altre forme di dichiarazioni di classe in C ++.)
Grazie a litb (Johannes Schaub) che ha estratto il capitolo e il verso in una delle sue risposte.
extern int i
è una dichiarazione, dal momento che introduce / specifica i
. Puoi averne quante extern int i
ne vuoi in ogni unità di compilazione. int i
, tuttavia, è una definizione. Indica lo spazio per l'intero in questa unità di traduzione e consiglia al linker di collegare tutti i riferimenti a i
questa entità. Se hai più o meno esattamente di una di queste definizioni, il linker si lamenterà.
int i;
in ambito file / ambito globale o funzione è una definizione sia in C che in C ++. In C perché alloca l'archiviazione e in C ++ perché non ha l'identificatore esterno o una specifica di collegamento. Questi equivalgono alla stessa cosa, che è ciò che dice sbi: in entrambi i casi questa dichiarazione specifica l'oggetto al quale devono essere collegati tutti i riferimenti a "i" in tale ambito.
struct A { double f(int, double); double f(int, double); };
ovviamente non valido. È consentito altrove però. Ci sono alcuni luoghi dove è possibile dichiarare le cose, ma non definiscono anche: void f() { void g(); }
valida, ma non quanto segue: void f() { void g() { } };
. Che cos'è una definizione e che una dichiarazione ha regole sottili quando si tratta di modelli - attenzione! +1 per una buona risposta però.
Dallo standard C ++ sezione 3.1:
Una dichiarazione introduce i nomi in un'unità di traduzione o redige le dichiarazioni introdotte da dichiarazioni precedenti. Una dichiarazione specifica l'interpretazione e gli attributi di questi nomi.
Il prossimo paragrafo afferma (enfatizzare il mio) che una dichiarazione è una definizione a meno che ...
... dichiara una funzione senza specificare il corpo della funzione:
void sqrt(double); // declares sqrt
... dichiara un membro statico all'interno di una definizione di classe:
struct X
{
int a; // defines a
static int b; // declares b
};
... dichiara un nome di classe:
class Y;
... contiene la extern
parola chiave senza inizializzatore o corpo della funzione:
extern const int i = 0; // defines i
extern int j; // declares j
extern "C"
{
void foo(); // declares foo
}
... o è una dichiarazione typedef
o using
.
typedef long LONG_32; // declares LONG_32
using namespace std; // declares std
Ora, per la grande ragione per cui è importante capire la differenza tra una dichiarazione e una definizione: la regola della definizione unica . Dalla sezione 3.2.1 della norma C ++:
Nessuna unità di traduzione deve contenere più di una definizione di variabile, funzione, tipo di classe, tipo di enumerazione o modello.
struct x {static int b = 3; };
?
b
sia anche dichiarata const
. Vedere stackoverflow.com/a/3536513/1858225 e daniweb.com/software-development/cpp/threads/140739/... .
Dichiarazione: "Da qualche parte esiste un foo".
Definizione: "... ed eccolo qui!"
Ci sono casi limite interessanti in C ++ (alcuni anche in C). Prendere in considerazione
T t;
Può essere una definizione o una dichiarazione, a seconda del tipo 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".
In C ++, quando si usano i template, c'è un altro caso limite.
template <typename T>
struct X {
static int member; // declaration
};
template<typename T>
int X<T>::member; // definition
template<>
int X<bool>::member; // declaration!
L'ultima dichiarazione non era una definizione. È la dichiarazione di una specializzazione esplicita del membro statico di X<bool>
. Indica al compilatore: "Se si tratta di X<bool>::member
creare un'istanza , quindi non creare un'istanza della definizione del membro dal modello principale, ma utilizzare la definizione trovata altrove". Per renderlo una definizione, è necessario fornire un inizializzatore
template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.
Dichiarazione
Le dichiarazioni indicano al compilatore che esiste un elemento o un nome di programma. Una dichiarazione introduce uno o più nomi in un programma. Le dichiarazioni possono verificarsi più di una volta in un programma. Pertanto, classi, strutture, tipi enumerati e altri tipi definiti dall'utente possono essere dichiarati per ogni unità di compilazione.
Definizione
Le definizioni specificano quale codice o dati descrive il nome. Un nome deve essere dichiarato prima di poter essere utilizzato.
class foo {};
è una definizione di classe , no?
Dallo standard C99, 6.7 (5):
Una dichiarazione specifica l'interpretazione e gli attributi di un insieme di identificatori. Una definizione di un identificatore è una dichiarazione per quell'identificatore che:
Dallo standard C ++, 3.1 (2):
Una dichiarazione è una definizione a meno che non dichiari una funzione senza specificare il corpo della funzione, contiene l'identificatore esterno o una specifica di collegamento e né un inizializzatore né un corpo di funzione, dichiara un membro di dati statici in una dichiarazione di classe, è un dichiarazione del nome della classe o è una dichiarazione typedef, una dichiarazione using o una direttiva using.
Quindi ci sono alcuni esempi.
È così interessante (o no, ma ne sono leggermente sorpreso), typedef int myint;
è una definizione in C99, ma solo una dichiarazione in C ++.
typedef
, ciò non significherebbe che potrebbe essere ripetuto in C ++, ma non in C99?
Da wiki.answers.com:
Il termine dichiarazione significa (in C) che stai dicendo al compilatore di tipo, dimensione e in caso di dichiarazione di funzione, tipo e dimensione dei suoi parametri di qualsiasi variabile, o tipo o funzione definiti dall'utente nel tuo programma. Nessuno spazio è riservato in memoria per qualsiasi variabile in caso di dichiarazione. Tuttavia il compilatore sa quanto spazio riservare nel caso in cui venga creata una variabile di questo tipo.
ad esempio, di seguito sono riportate tutte le dichiarazioni:
extern int a;
struct _tagExample { int a; int b; };
int myFunc (int a, int b);
La definizione d'altra parte significa che oltre a tutto ciò che fa la dichiarazione, lo spazio è anche riservato nella memoria. Puoi dire "DEFINIZIONE = DICHIARAZIONE + PRENOTAZIONE SPAZIO" di seguito sono riportati esempi di definizione:
int a;
int b = 0;
int myFunc (int a, int b) { return a + b; }
struct _tagExample example;
vedi Risposte .
struct foo {};
è una definizione , non una dichiarazione. Una dichiarazione di foo
sarebbe struct foo;
. Da ciò, il compilatore non sa quanto spazio riservare agli foo
oggetti.
struct foo;
è una dichiarazione, ma non indica al compilatore le dimensioni di pippo. Aggiungo che struct _tagExample { int a; int b; };
è una definizione. Quindi in questo contesto è fuorviante chiamarlo una dichiarazione. Naturalmente lo è, dal momento che tutte le definizioni sono dichiarazioni, ma sembra che tu stia suggerendo che non è una definizione. È una definizione di _tagExample.
Dal momento che non vedo una risposta pertinente a C ++ 11 eccone una.
Una dichiarazione è una definizione a meno che non dichiari a / n:
enum X : int;
template<typename T> class MyArray;
int add(int x, int y);
using IntVector = std::vector<int>;
static_assert(sizeof(int) == 4, "Yikes!")
;
Clausole aggiuntive ereditate da C ++ 03 dall'elenco precedente:
int add(int x, int y);
extern int a;
oppureextern "C" { ... };
class C { static int x; };
struct Point;
typedef int Int;
using std::cout;
using namespace NS;
Una dichiarazione modello è una dichiarazione. Una dichiarazione modello è anche una definizione se la sua dichiarazione definisce una funzione, una classe o un membro di dati statici.
Esempi dallo standard che distingue tra dichiarazione e definizione che ho trovato utile per comprendere le sfumature tra di loro:
// 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
Definizione:
extern int a; // Declaration
int a; // Definition
a = 10 // Initialization
int b = 10; // Definition & Initialization
La definizione associa la variabile a un tipo e alloca la memoria, mentre la dichiarazione specifica solo il tipo ma non alloca la memoria. La dichiarazione è più utile quando si desidera fare riferimento alla variabile prima della definizione.
* Non confondere la definizione con l'inizializzazione. Entrambi sono diversi, l'inizializzazione dà valore alla variabile. Vedi l'esempio sopra.
Di seguito sono riportati alcuni esempi di definizione.
int a;
float b;
double c;
Ora dichiarazione di funzione:
int fun(int a,int b);
Nota il punto e virgola alla fine della funzione, quindi dice che è solo una dichiarazione. Il compilatore sa che da qualche parte nel programma tale funzione verrà definita con quel prototipo. Ora se il compilatore riceve una funzione chiama qualcosa del genere
int b=fun(x,y,z);
Il compilatore genererà un errore dicendo che non esiste tale funzione. Perché non ha alcun prototipo per quella funzione.
Nota la differenza tra due programmi.
Programma 1
#include <stdio.h>
void print(int a)
{
printf("%d",a);
}
main()
{
print(5);
}
In questo, viene dichiarata e definita anche la funzione di stampa. Poiché la chiamata di funzione sta arrivando dopo la definizione. Ora guarda il prossimo programma.
Programma 2
#include <stdio.h>
void print(int a); // In this case this is essential
main()
{
print(5);
}
void print(int a)
{
printf("%d",a);
}
È essenziale perché la chiamata di funzione precede la definizione, quindi il compilatore deve sapere se esiste una tale funzione. Quindi dichiariamo la funzione che informerà il compilatore.
Definizione:
Questa parte della definizione di una funzione è chiamata Definizione. Dice cosa fare all'interno della funzione.
void print(int a)
{
printf("%d",a);
}
int a; //declaration; a=10; //definition
Questo è completamente sbagliato. Quando si parla di oggetti di durata della memoria automatica (oggetti dichiarati all'interno di una definizione di funzione che non sono dichiarati con un altro identificatore della classe di memoria come extern) si tratta sempre di definizioni.
definizione significa funzione effettiva scritta e dichiarazione significa funzione di dichiarazione semplice per es
void myfunction(); //this is simple declaration
e
void myfunction()
{
some statement;
}
questa è la definizione della funzione myfunction
Regola del pollice:
Una dichiarazione indica al compilatore come interpretare i dati della variabile in memoria. Questo è necessario per ogni accesso.
Una definizione riserva la memoria per rendere esistente la variabile. Questo deve avvenire esattamente una volta prima del primo accesso.
Per capire i nomi, concentriamoci prima sui verbi.
dichiarare - annunciare ufficialmente; proclamare
definire - per mostrare o descrivere (qualcuno o qualcosa) in modo chiaro e completo
Quindi, quando dichiari qualcosa, dici semplicemente di cosa si tratta .
// declaration
int sum(int, int);
Questa riga dichiara una funzione C chiamata sum
che accetta due argomenti di tipo int
e restituisce un int
. Tuttavia, non puoi ancora usarlo.
Quando fornisci come funziona effettivamente , questa è la sua definizione.
// definition
int sum(int x, int y)
{
return x + y;
}
Per comprendere la differenza tra dichiarazione e definizione, è necessario vedere il codice 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)
e questa è solo la definizione:
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)
Come vedi nulla cambia.
La dichiarazione è diversa dalla definizione perché fornisce informazioni utilizzate solo dal compilatore. Ad esempio uint8_t dice al compilatore di usare la funzione asb movb.
Guarda quello:
uint def; | no instructions
printf("some stuff..."); | [...] callq 0x400450 <printf@plt>
def=5; | movb $0x5,-0x45(%rbp)
La dichiarazione non ha un'istruzione equivalente perché non è qualcosa da eseguire.
Inoltre la dichiarazione indica al compilatore l'ambito della variabile.
Possiamo dire che la dichiarazione è un'informazione utilizzata dal compilatore per stabilire l'uso corretto della variabile e per quanto tempo parte della memoria appartiene a una determinata variabile.
Non potresti affermare nei termini più generali possibili che una dichiarazione è un identificatore in cui non è allocata alcuna memoria e una definizione alloca effettivamente la memoria da un identificatore dichiarato?
Un pensiero interessante: un modello non può allocare l'archiviazione fino a quando la classe o la funzione non sono collegate alle informazioni sul tipo. Quindi l'identificatore del modello è una dichiarazione o una definizione? Dovrebbe essere una dichiarazione poiché non è stata allocata alcuna memoria e si sta semplicemente "prototipando" la classe o la funzione del modello.
template<class T> struct foo;
è una dichiarazione di modello , così come questa template<class T> void f();
. Le definizioni dei modelli rispecchiano le definizioni di classi / funzioni allo stesso modo. (Si noti che il nome di un modello non è un tipo o un nome di funzione . Un punto in cui è possibile visualizzarlo è quando non è possibile passare un modello come parametro di tipo di un altro modello. Se si desidera passare modelli anziché tipi, è necessario disporre dei parametri del modello di modello. )
Trova le risposte simili qui: intervista domande tecniche in C .
Una dichiarazione fornisce un nome al programma; una definizione fornisce una descrizione univoca di un'entità (ad esempio tipo, istanza e funzione) all'interno del programma. Le dichiarazioni possono essere ripetute in un determinato ambito, introducono un nome in un determinato ambito.
Una dichiarazione è una definizione a meno che:
Una definizione è una dichiarazione a meno che:
Questo suonerà davvero di cattivo gusto, ma è il modo migliore in cui sono stato in grado di mantenere i termini nella mia testa:
Dichiarazione: Picture Thomas Jefferson mentre tiene un discorso ... "DICHIARO QUESTO QUESTO FOO ESISTE IN QUESTO CODICE SORGENTE !!!"
Definizione: immagina un dizionario, stai cercando Foo e cosa significa in realtà.
Secondo il manuale della libreria GNU C ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )
In C, una dichiarazione fornisce semplicemente informazioni sull'esistenza di una funzione o variabile e ne fornisce il tipo. Per una dichiarazione di funzione, potrebbero essere fornite anche informazioni sui tipi dei suoi argomenti. Lo scopo delle dichiarazioni è di consentire al compilatore di elaborare correttamente i riferimenti alle variabili e funzioni dichiarate. Una definizione, d'altra parte, alloca l'archiviazione per una variabile o dice cosa fa una funzione.
Il concetto di Dichiarazione e Definizione costituirà una trappola quando si utilizza la classe di archiviazione esterna perché la definizione si troverà in un'altra posizione e si sta dichiarando la variabile nel file di codice locale (pagina). Una differenza tra C e C ++ è che in C le dichiarazioni sono fatte normalmente all'inizio di una funzione o di una tabella codici. In C ++ non è così. Puoi dichiarare in un luogo di tua scelta.
Il mio esempio preferito è "int Num = 5" qui la tua variabile è 1. definita come int 2. dichiarata come Num e 3. istanziata con un valore di cinque. Noi
Una classe o struttura ti consente di cambiare il modo in cui gli oggetti verranno definiti quando verrà utilizzato in seguito. Per esempio
Quando impariamo a programmare questi due termini sono spesso confusi perché spesso facciamo entrambi allo stesso tempo.
Fasi di una generazione eseguibile:
(1) pre-processore -> (2) traduttore / compilatore -> (3) linker
Nella fase 2 (traduttore / compilatore), le dichiarazioni di dichiarazione nel nostro codice dicono al compilatore che queste cose useremo in futuro e puoi trovare la definizione in seguito, il significato è:
traduttore assicurarsi che: che cosa è che cosa? significa dichiarazione
e (3) fase (linker) ha bisogno di definizione per legare le cose
Linker si assicura che: dov'è cosa? significa definizione
Ci sono alcune definizioni molto chiare sparse in tutta K&R (2a edizione); aiuta a metterli in un posto e a leggerli come uno:
"Definizione" si riferisce al luogo in cui viene creata o assegnata la memoria; "dichiarazione" si riferisce ai luoghi in cui è indicata la natura della variabile ma non è stata allocata alcuna memoria. [P. 33]
...
È importante distinguere tra la dichiarazione di una variabile esterna e la sua definizione . Una dichiarazione annuncia le proprietà di una variabile (principalmente il suo tipo); una definizione causa anche l'archiviazione dell'archiviazione. Se le linee
int sp; double val[MAXVAL]
appaiono al di fuori di qualsiasi funzione, definiscono le variabili esterne
sp
eval
, causano l'archiviazione dell'archiviazione e fungono anche da dichiarazione per il resto del file sorgente.D'altra parte, le linee
extern int sp; extern double val[];
dichiarare per il resto del file sorgente che
sp
è unint
e cheval
è undouble
array (la cui dimensione è determinata altrove), ma non creano le variabili né riservano spazio per essi.Deve essercene solo uno definizione di una variabile esterna tra tutti i file che compongono il programma di origine. ... Le dimensioni dell'array devono essere specificate con la definizione, ma sono facoltative con una
extern
dichiarazione. [pp. 80-81]...
Le dichiarazioni specificano l'interpretazione data a ciascun identificatore; non riservano necessariamente la memoria associata all'identificatore. Le dichiarazioni che riservano l'archiviazione sono chiamate definizioni . [p. 210]
Dichiarazione significa dare nome e tipo a una variabile (in caso di dichiarazione variabile), ad esempio:
int i;
oppure assegnare nome, tipo di ritorno e tipo di parametro a una funzione senza corpo (in caso di dichiarazione di funzione), ad esempio:
int max(int, int);
mentre definizione significa assegnare valore a una variabile (in caso di definizione variabile), ad esempio:
i = 20;
o fornire / aggiungere corpo (funzionalità) a una funzione è chiamata definizione di funzione, ad es .:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
molte dichiarazioni e definizioni temporali possono essere fatte insieme come:
int i=20;
e:
int max(int a, int b)
{
if(a>b) return a;
return b;
}
Nei casi precedenti definiamo e dichiariamo variabili i
e function max()
.
int x;