Qual è la differenza tra una definizione e una dichiarazione?


858

Il significato di entrambi mi sfugge.


91
@Lasse: non vero. Una definizione definisce e dichiara ;-)
Steve Jessop,

13
Francamente, ho avuto molti problemi ad imparare quale fosse, quindi non ho trovato i nomi ovvi. Non ho avuto problemi con i significati, solo quali nomi associare ai significati.
David Thornley,

6
Tuttavia, non è una domanda duplicata, dal momento che si tratta di C / C ++, mentre quell'altra domanda riguardava tutte le lingue, o nessuna, in generale. Ha solo risposte duplicate (poiché in quell'altra domanda, alcune risposte hanno scelto di ignorare tutto il linguaggio tranne C e / o C ++).
Steve Jessop,

5
@DavidThornley Uso questo trucco: una definizione fornisce una descrizione più dettagliata di una determinata variabile o funzione. Per ricordare questo, ricordo che il centro della parola "definizione" ha una somiglianza con la parola "più fine". :)
Marco Leogrande,

4
Incredibile quanta merda c'è su questa domanda. Va solo a dimostrare quanto questo linguaggio sia frainteso e in che modo questi malintesi vengano regolarmente propagati . È triste, davvero.
Corse di leggerezza in orbita

Risposte:


858

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.


2
@unknown: o il tuo compilatore non funziona perché hai copiato male il codice di sbi. Ad esempio, 6.7.2 (2) in N1124: "Tutte le dichiarazioni che si riferiscono allo stesso oggetto o funzione devono avere un tipo compatibile; in caso contrario, il comportamento non è definito."
Steve Jessop,

4
@Brian: "extern int i;" dice che sono un int da qualche parte, non ti preoccupare. "int i;" significa che i è un int e il suo indirizzo e ambito sono determinati qui.
David Thornley,

12
@Brian: ti sbagli. extern int iè una dichiarazione, dal momento che introduce / specifica i. Puoi averne quante extern int ine 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 iquesta entità. Se hai più o meno esattamente di una di queste definizioni, il linker si lamenterà.
sbi,

4
@Brian 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.
Steve Jessop,

4
@unknown, attenzione che non puoi dichiarare i membri nell'ambito della classe : 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ò.
Johannes Schaub - lett.

168

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 externparola 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 typedefo 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.


"dichiara un membro statico all'interno di una definizione di classe" - Questo è vero anche se il membro statico è inizializzato, giusto? Possiamo fare l'esempio struct x {static int b = 3; };?
RJFalconer

@RJFalconer Hai ragione; inizializzazione non senza necessariamente trasformare una dichiarazione in una definizione (al contrario di quanto ci si potrebbe aspettare, sicuramente ho trovato questo sorprendente). La tua modifica all'esempio è in realtà illegale a meno che non bsia anche dichiarata const. Vedere stackoverflow.com/a/3536513/1858225 e daniweb.com/software-development/cpp/threads/140739/... .
Kyle Strand,

1
Questo è interessante per me. Secondo la tua risposta, sembra che in C ++ una dichiarazione sia anche una definizione (con eccezioni), mentre nello standard C è formulata dall'altra prospettiva (C99, sezione 6.7, Dichiarazioni): "Una definizione di un identificatore è una dichiarazione per quell'identificatore che: [seguito da criteri per casi diversi] ". Diversi modi di vederlo, suppongo. :)
Victor Zamanian,

La dichiarazione è per il compilatore di accettare un nome (per dire al compilatore che il nome è legale, il nome è introdotto con intenzione non un errore di battitura). La definizione è la posizione in cui un nome e il suo contenuto sono associati. La definizione viene utilizzata dal linker per collegare un riferimento al nome al contenuto del nome.
Gab 是 好人

137

Dichiarazione: "Da qualche parte esiste un foo".

Definizione: "... ed eccolo qui!"


3
La dichiarazione è per il compilatore di accettare un nome (per dire al compilatore che il nome è legale, il nome è introdotto con intenzione non un errore di battitura). La definizione è la posizione in cui un nome e il suo contenuto sono associati. La definizione viene utilizzata dal linker per collegare un riferimento al nome al contenuto del nome.
Gab 是 好人

46

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>::membercreare 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.

35

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.


Ehm, non è che puoi anche definire classi ed enumerazioni in ogni unità di compilazione? Almeno ho inserito le definizioni delle classi nelle mie intestazioni e le includo ovunque. Ehm, class foo {}; è una definizione di classe , no?
sbi,

1
Sì. Tuttavia, "class foo;" è una dichiarazione. Indica al compilatore che foo è una classe. "class foo {};" è una definizione. Indica al compilatore esattamente che tipo di classe è.
David Thornley,

1
L'eccezione sono i nomi dei membri della classe che possono essere utilizzati prima di essere dichiarati.
Johannes Schaub - lett.

1
Sì, questo è ciò che intendevo. Quindi puoi fare quanto segue: struct foo {void b () {f (); } void f (); }, f è visibile anche se non ancora dichiarato. Funziona anche come segue: struct foo {void b (int = bar ()); typedef int bar; } ;. È visibile prima della sua dichiarazione in "tutti i corpi funzione, argomenti predefiniti, inizializzatori ctor del costruttore". Non nel tipo restituito :(
Johannes Schaub - litb

1
@litb: non è visibile prima della sua dichiarazione, è solo che l' uso dell'identificatore viene spostato dietro la dichiarazione. Sì, lo so, l'effetto è lo stesso per molti casi. Ma non per tutti i casi, motivo per cui penso che dovremmo usare la spiegazione precisa. - Ops, aspetta. È visibile negli argomenti predefiniti? Bene, questo sicuramente distrugge la mia comprensione. Dannazione! <pouts>
sbi

22

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:

  • per un oggetto, fa sì che la memoria sia riservata per quell'oggetto;
  • per una funzione, include il corpo della funzione;
  • per una costante di enumerazione o il nome typedef, è la (unica) dichiarazione dell'identificatore.

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 ++.


@onebyone: Per quanto riguarda il typedef, ciò non significherebbe che potrebbe essere ripetuto in C ++, ma non in C99?
sbi,

Questo è ciò che mi ha sorpreso, e per quanto riguarda una singola unità di traduzione, sì, c'è questa differenza. Ma chiaramente un typedef può essere ripetuto in C99 in diverse unità di traduzione. C non ha una "regola di definizione" esplicita come C ++, quindi le regole che ha lo consentono. C ++ ha scelto di cambiarlo in una dichiarazione, ma anche la regola di una definizione elenca a quali tipi di cose si applica e typedefs non è uno di questi. Quindi le ripetizioni sarebbero consentite in C ++ sotto l'ODR così come è formulato, anche se un typedef era una definizione. Sembra inutilmente pignolo.
Steve Jessop,

... ma immagino che l'elenco dell'ODR in realtà elenchi tutte le cose di cui è possibile avere delle definizioni. In tal caso, l'elenco è effettivamente ridondante ed è lì solo per essere utile.
Steve Jessop,

Cosa dice la definizione ODR dello standard sulle definizioni di classe? Essi devono essere ripetute.
sbi,

2
@sbi: ODR afferma "(1) Nessuna unità di traduzione deve contenere più di una definizione di qualsiasi ... tipo di classe" e "(5) In un programma può esserci più di una definizione di un tipo di classe ... ogni definizione appare in una diversa unità di traduzione "e quindi alcuni requisiti extra che equivalgono a" le definizioni sono le stesse ".
Steve Jessop,

17

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 .


3
Anche questo è sbagliato (anche se molto più vicino degli altri): struct foo {};è una definizione , non una dichiarazione. Una dichiarazione di foosarebbe struct foo;. Da ciò, il compilatore non sa quanto spazio riservare agli foooggetti.
sbi,

1
@Marcin: sbi sta dicendo che "il compilatore sa quanto spazio riservare nel caso in cui venga creata una variabile di questo tipo" non è sempre vero. 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.
Steve Jessop,

1
@Marcin Gil: Il che significa che la wiki "Risposte" non è sempre precisa. Devo votare per disinformazione qui.
David Thornley,

1
Impariamo che ciò che l'adatapost citato è vero ma non (IMO) risponde veramente alla domanda. Ciò che Marcin ha citato è falso. Citando gli standard è vero e risponde alla domanda, ma è molto difficile da capire.
Steve Jessop,

1
@ David Thornley - non è un problema :) Ecco di cosa tratta questo sito. Noi selezioniamo e verificare informazioni.
Marcin Gil,

13

Aggiornamento C ++ 11

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 opaco - enum X : int;
  • parametro template - T intemplate<typename T> class MyArray;
  • dichiarazione di parametro - x ed y inint add(int x, int y);
  • dichiarazione alias - using IntVector = std::vector<int>;
  • dichiarazione di asserzione statica - static_assert(sizeof(int) == 4, "Yikes!")
  • dichiarazione di attributo (definita dall'implementazione)
  • dichiarazione vuota ;

Clausole aggiuntive ereditate da C ++ 03 dall'elenco precedente:

  • dichiarazione di funzione - aggiungere aint add(int x, int y);
  • specificatore esterno contenente una dichiarazione o un identificatore di collegamento - extern int a;oppureextern "C" { ... };
  • membro di dati statici in una classe - x inclass C { static int x; };
  • dichiarazione di classe / struttura - struct Point;
  • dichiarazione typedef - typedef int Int;
  • usando la dichiarazione - using std::cout;
  • usando la direttiva - 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

6

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);
}

2
int a; //declaration; a=10; //definitionQuesto è 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.
Joey Pabalinas,

La principale differenza da comprendere è che una dichiarazione dice "esiste qualcosa da qualche parte che ha questi tratti (tipo ecc.)", Mentre una definizione dice "Sto dichiarando qualcosa con questi tratti, e lo sto anche istanziando come bene." Poiché non è possibile inoltrare in questo modo oggetti di durata della memorizzazione automatica, saranno sempre definizioni.
Joey Pabalinas,

Tranne forse alcuni strani casi angolari dattiloscritti che mi dimentico sempre, una regola empirica è che tutte le definizioni sono dichiarazioni. Pensaci; quando stai istanziando qualcosa, devi anche dire al compilatore che quella cosa esiste e quali sono i suoi tratti giusti?
Joey Pabalinas,

Aggiornato la risposta secondo il tuo primo commento. tuttavia non sono d'accordo con questo commento "quando stai istanziando qualcosa, devi anche dire al compilatore che quella cosa esiste". Non specifichiamo sempre il tipo di SSL durante l'istanza. Es: a = 10. Non stiamo specificando alcun "tratto" di un qui.
SRIDHARAN,

4

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


1
E i tipi e gli oggetti?
sabato

4

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.


2
Questo vale solo per gli oggetti. Che dire di tipi e funzioni?
Corse di leggerezza in orbita

4

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 sumche accetta due argomenti di tipo inte 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;
}

3

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.


2

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.


1
La tua definizione non è di per sé sbagliata, ma la "definizione di archiviazione" sembra sempre imbarazzante quando si tratta di definizioni di funzioni. Per quanto riguarda i modelli: questa 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. )
sbi,

Concordato sul fatto che la "definizione di memoria" è scomoda, soprattutto per quanto riguarda le definizioni delle funzioni. La dichiarazione è int foo () e la definizione è int foo () {// alcuni codici qui ..}. Di solito ho bisogno di avvolgere il mio piccolo cervello con concetti che mi sono familiari - lo "stoccaggio" è un modo per tenerlo dritto almeno per me ... :)

2

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:

  • La dichiarazione dichiara una funzione senza specificarne il corpo,
  • La dichiarazione contiene un identificatore esterno e nessun inizializzatore o corpo della funzione,
  • Dichiarazione è la dichiarazione di un membro di dati di classe statica senza una definizione di classe,
  • La dichiarazione è una definizione di nome di classe,

Una definizione è una dichiarazione a meno che:

  • La definizione definisce un membro di dati di classe statica,
  • La definizione definisce una funzione membro non incorporata.

1

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à.


1

Una dichiarazione presenta un nome simbolo al compilatore. Una definizione è una dichiarazione che alloca spazio per il simbolo.

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

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

1

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.


0

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.


1
Questo confonde la dichiarazione con la definizione ed è chiaramente sbagliato.
sabato

0

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

  • Definire il tipo di un oggetto, che può essere incorporato o una classe o struttura.
  • Dichiara il nome di un oggetto, quindi è stato dichiarato qualsiasi cosa con un nome che includa Variabili, Funzioni, ecc.

Una classe o struttura ti consente di cambiare il modo in cui gli oggetti verranno definiti quando verrà utilizzato in seguito. Per esempio

  • Si può dichiarare una variabile o matrice eterogenea che non sono specificamente definite.
  • Usando un offset in C ++ puoi definire un oggetto che non ha un nome dichiarato.

Quando impariamo a programmare questi due termini sono spesso confusi perché spesso facciamo entrambi allo stesso tempo.


Non capisco perché così tante persone abbiano votato a favore della risposta di SBI. Ho votato a favore della risposta di Bjhend, che è stata abbastanza buona, concisa, accurata e molto più attuale della mia. Ero triste nel vedere di essere stata la prima persona a farlo in 4 anni.
Jason K.

0

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


0

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 spe val, 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 che valè un doublearray (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 externdichiarazione. [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]


-1

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 ie function max().


la media effettiva della definizione se assegnare valore / corpo a una variabile / funzione mentre dichiarazione significa fornire nome, tipo a una variabile / funzione
Puneet Purohit

Puoi definire qualcosa senza assegnargli un valore.
Corse di leggerezza in orbita

1
Proprio così:int x;
Razze di leggerezza in orbita

è una dichiarazione della variabile x non la sua
definizione

2
No, sono entrambi. Stai confondendo la definizione con l'inizializzazione.
Corse di leggerezza in orbita,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.