Jaka jest różnica między definicją a deklaracją?


857

Znaczenie obu mi umyka.


91
@Lasse: nieprawda. Definicja zarówno definiuje, jak i deklaruje ;-)
Steve Jessop,

13
Szczerze mówiąc, miałem wiele problemów z nauką, co było tym, więc nie uważałem tych nazw za oczywiste. Nie miałem problemu ze znaczeniami, tylko jakie imiona skojarzyć ze znaczeniami.
David Thornley,

6
Nie jest to jednak duplikat pytania, ponieważ dotyczy to C / C ++, podczas gdy inne pytanie dotyczy wszystkich języków lub nie ma go wcale. Ma tylko zduplikowane odpowiedzi (ponieważ w tym drugim pytaniu niektóre odpowiedzi zignorowały wszystkie języki oprócz C i / lub C ++).
Steve Jessop,

5
@DavidThornley Używam tej sztuczki: definicja daje dokładniejszy opis danej zmiennej lub funkcji. Aby to zapamiętać, przypominam sobie, że środek słowa „definicja” przypomina słowo „drobniejszy”. :)
Marco Leogrande

4
Zadziwiające, ile bzdur jest w tym pytaniu. Po prostu pokazuje, jak bardzo ten język jest źle rozumiany i jak te nieporozumienia są rutynowo rozpowszechniane . To naprawdę smutne.
Lekkość ściga się na orbicie

Odpowiedzi:


858

Deklaracja wprowadza identyfikator i opisuje jej typ, czy to typ obiektu lub funkcji. Deklaracja jest tym, czego kompilator potrzebuje, aby zaakceptować odwołania do tego identyfikatora. Są to deklaracje:

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

Definicja faktycznie instancję / narzędzia tego identyfikatora. Właśnie tego linker potrzebuje , aby połączyć referencje z tymi jednostkami. Są to definicje odpowiadające powyższym deklaracjom:

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

Zamiast deklaracji można zastosować definicję.

Identyfikator może być deklarowany tak często, jak chcesz. Dlatego w C i C ++ dozwolone są następujące czynności:

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

Jednak musi być zdefiniowany dokładnie raz. Jeśli zapomnisz zdefiniować coś, co gdzieś zostało zadeklarowane i do którego się odwołuje, linker nie wie, do czego prowadzić link i narzeka na brakujące symbole. Jeśli zdefiniujesz coś więcej niż jeden raz, linker nie wie, do której definicji odwołuje się odwołanie, i skarży się na powielone symbole.


Ponieważ wciąż pojawia się debata na temat deklaracji klasy a definicji klasy w C ++ (w odpowiedziach i komentarzach do innych pytań), tutaj wkleję cytat ze standardu C ++.
W wersji 3.1 / 2 C ++ 03 mówi:

Deklaracja jest definicją, chyba że [...] jest deklaracją nazwy klasy [...].

3.1 / 3 następnie podaje kilka przykładów. Pośród nich:

[Przykład: [...]
struct S {int a; int b; }; // definiuje S, S :: a i S :: b [...]
struct S; // deklaruje S
—Przykład

Podsumowując: standard C ++ uważa struct x;się zgłoszenie i definicja . (Innymi słowy, „deklaracja przekazania” jest myląca , ponieważ w C ++ nie ma innych form deklaracji klas.)struct x {};

Dzięki litb (Johannes Schaub), który wykopał właściwy rozdział i werset w jednej ze swoich odpowiedzi.


2
@unknown: albo twój kompilator nie działa, źle skopiowałeś kod sbi. Na przykład 6.7.2 (2) w N1124: „Wszystkie deklaracje odnoszące się do tego samego obiektu lub funkcji powinny mieć zgodny typ; w przeciwnym razie zachowanie jest niezdefiniowane”.
Steve Jessop,

4
@Brian: „extern int i;” mówi, że jestem gdzieś intem, nie martw się tym. „int i;” oznacza, że ​​i jest liczbą całkowitą, a jej adres i zakres są określone tutaj.
David Thornley,

12
@Brian: Mylisz się. extern int ijest deklaracją, ponieważ po prostu wprowadza / określa i. W extern int ikażdej jednostce kompilacyjnej możesz mieć tyle, ile chcesz. int ijest jednak definicją. Oznacza miejsce na liczbę całkowitą w tej jednostce tłumaczeniowej i radzi linkerowi, aby powiązał wszystkie odniesienia iz tym podmiotem. Jeśli masz więcej niż jedną z tych definicji, linker narzeka.
sbi

4
@Brian int i;w zakresie pliku / zasięgu globalnym lub zasięgu funkcji jest definicją zarówno w C, jak i C ++. W C, ponieważ alokuje pamięć, aw C ++, ponieważ nie ma specyfikatora zewnętrznego ani specyfikacji powiązania. Sprowadza się to do tego samego, co mówi sbi: w obu przypadkach deklaracja określa obiekt, z którym muszą być powiązane wszystkie odniesienia do „i” w tym zakresie.
Steve Jessop,

4
@unknown, strzeż się, że nie możesz ponownie ustawić członków w zakresie klasy : struct A { double f(int, double); double f(int, double); };oczywiście nieważne. Jest to dozwolone gdzie indziej. Istnieje kilka miejsc, gdzie można zadeklarować rzeczy, ale nie określają też: void f() { void g(); }ważny, ale nie dodaje się: void f() { void g() { } };. Co to jest definicja, a co deklaracja ma subtelne reguły, jeśli chodzi o szablony - uwaga! +1 za dobrą odpowiedź.
Johannes Schaub - litb

168

Ze standardowej sekcji C ++ sekcja 3.1:

A deklaracja wprowadza nazwy do jednostki lub redeclares tłumaczenie nazw wprowadzonych przez wcześniejszych deklaracji. Deklaracja określa interpretację i atrybuty tych nazw.

Następny akapit stwierdza (moje podkreślenie), że deklaracja jest definicją, chyba że ...

... deklaruje funkcję bez określania jej treści:

void sqrt(double);  // declares sqrt

... deklaruje element statyczny w definicji klasy:

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

... deklaruje nazwę klasy:

class Y;

... zawiera externsłowo kluczowe bez inicjatora lub treści funkcji:

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

... lub jest oświadczeniem typedeflub using.

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

Teraz z ważnego powodu, dla którego ważne jest zrozumienie różnicy między deklaracją a definicją: Reguła One Definition . Z sekcji 3.2.1 standardu C ++:

Żadna jednostka tłumacząca nie może zawierać więcej niż jednej definicji jakiejkolwiek zmiennej, funkcji, typu klasy, typu wyliczenia lub szablonu.


„deklaruje element statyczny w definicji klasy” - to prawda, nawet jeśli element statyczny jest zainicjowany, prawda? Czy możemy zrobić przykład struct x {static int b = 3; };?
RJFalconer,

@RJFalconer Masz rację; inicjalizacji nie nie koniecznie włączyć oświadczenie w definicji (wbrew temu, co można by się spodziewać, na pewno znalazłem to zaskakujące). Twoja modyfikacja tego przykładu jest w rzeczywistości nielegalna, chyba że bzostanie również zadeklarowana const. Zobacz stackoverflow.com/a/3536513/1858225 i daniweb.com/software-development/cpp/threads/140739/... .
Kyle Strand

1
To mnie interesuje. Zgodnie z odpowiedzią wydaje się, że w C ++ deklaracja jest również definicją (z wyjątkami), podczas gdy w standardzie C jest wyrażona z innej perspektywy (C99, sekcja 6.7, Deklaracje): „ Definicja identyfikatora to deklaracja dla tego identyfikatora, która: [następuje po kryteriach dla różnych przypadków] ". Różne sposoby patrzenia na to, jak sądzę. :)
Victor Zamanian

Deklaracja służy kompilatorowi do zaakceptowania nazwy (aby poinformować kompilator, że nazwa jest legalna, nazwa jest wprowadzana z zamiarem, a nie literówka). Definicja to miejsce, w którym powiązana jest nazwa i jej treść. Definicja jest używana przez linker do połączenia odwołania nazwy do treści nazwy.
Gab 是 好人

137

Deklaracja: „Gdzieś istnieje foo”.

Definicja: „... i oto jest!”


3
Deklaracja służy kompilatorowi do zaakceptowania nazwy (aby poinformować kompilator, że nazwa jest legalna, nazwa jest wprowadzana z zamiarem, a nie literówka). Definicja to miejsce, w którym powiązana jest nazwa i jej treść. Definicja jest używana przez linker do połączenia odwołania nazwy do treści nazwy.
Gab 是 好人

46

W C ++ są interesujące przypadki krawędzi (niektóre z nich również w C). Rozważać

T t;

Może to być definicja lub deklaracja, w zależności od typu 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".

W C ++, gdy używasz szablonów, istnieje inny przypadek krawędzi.

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

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

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

Ostatnia deklaracja nie była definicją. Jest to deklaracja wyraźnej specjalizacji statycznego członka X<bool>. Mówi kompilatorowi: „Jeśli chodzi o tworzenie instancji X<bool>::member, nie twórz instancji definicji elementu członkowskiego z podstawowego szablonu, ale użyj definicji znalezionej gdzie indziej”. Aby była to definicja, musisz podać inicjator

template<>
int X<bool>::member = 1; // definition, belongs into a .cpp file.

35

Deklaracja

Deklaracje informują kompilator, że istnieje element lub nazwa programu. Deklaracja wprowadza jedną lub więcej nazw do programu. Deklaracje mogą występować w programie więcej niż jeden raz. Dlatego klasy, struktury, typy wyliczone i inne typy zdefiniowane przez użytkownika mogą być deklarowane dla każdej jednostki kompilacji.

Definicja

Definicje określają kod lub dane, które opisuje nazwa. Nazwa musi zostać zadeklarowana przed użyciem.


Hm, czy nie jest tak, że można nawet zdefiniować klasy i wyliczenia w każdej jednostce kompilacji? Przynajmniej umieszczam definicje klas w moich nagłówkach i uwzględniam je w całym tekście. Eee, class foo {}; czy to definicja klasy , prawda?
sbi

1
Tak. Jednak „class foo;” jest deklaracją. Mówi kompilatorowi, że foo jest klasą. „class foo {};” jest definicją. Mówi kompilatorowi dokładnie, co to za klasa foo.
David Thornley,

1
Wyjątkiem są nazwy członków klasy, których można użyć przed zadeklarowaniem.
Johannes Schaub - litb

1
Tak, o to mi chodziło. Możesz więc wykonać następujące czynności: struct foo {void b () {f (); } void f (); }, f jest widoczne, nawet jeśli jeszcze nie zostało zadeklarowane. Działa również następująco: struct foo {void b (int = bar ()); typedef int bar; } ;. Jest widoczny przed deklaracją w „wszystkich ciałach funkcji, domyślnych argumentach, inicjatorach ctor-inicjatora”. Brak w polu zwrotu :(
Johannes Schaub - litb

1
@litb: Nie jest widoczne przed deklaracją, po prostu użycie identyfikatora jest przesunięte za deklarację. Tak, wiem, efekt jest taki sam w wielu przypadkach. Ale nie we wszystkich przypadkach, dlatego uważam, że powinniśmy użyć dokładnego wyjaśnienia. - Ups, czekaj. Jest widoczny w domyślnych argumentach? Cóż, to z pewnością powoduje spustoszenie w moim zrozumieniu. Cholera! <pouts>
sbi

22

Ze standardu C99 6,7 (5):

Deklaracja określa interpretację i atrybuty zestawu identyfikatorów. Definicja identyfikatora jest deklaracja dla tego identyfikatora, że:

  • dla obiektu powoduje, że pamięć jest zarezerwowana dla tego obiektu;
  • dla funkcji obejmuje treść funkcji;
  • dla stałej wyliczenia lub nazwy typedef jest (jedyną) deklaracją identyfikatora.

Ze standardu C ++ 3.1 (2):

Deklaracja jest definicją, chyba że deklaruje funkcję bez określania treści funkcji, zawiera specyfikator zewnętrzny lub specyfikację powiązania i nie jest inicjatorem ani ciałem funkcji, deklaruje element danych statycznych w deklaracji klasy, jest to deklaracja nazwy klasy lub deklaracja typedef, deklaracja użycia lub dyrektywa użytkowania.

Następnie jest kilka przykładów.

Tak interesująco (lub nie, ale jestem nieco zaskoczony), typedef int myint;to definicja w C99, ale tylko deklaracja w C ++.


@onebyone: Jeśli chodzi o typedef, czy to nie znaczy, że można to powtórzyć w C ++, ale nie w C99?
sbi

Zaskoczyło mnie to, a jeśli chodzi o jedną jednostkę tłumaczeniową, to jest różnica. Ale oczywiście czcionkę typową można powtórzyć w C99 w różnych jednostkach tłumaczeniowych. C nie ma wyraźnej „reguły jednej definicji”, takiej jak C ++, więc reguły, które ma, po prostu na to pozwalają. C ++ zdecydował się zmienić go na deklarację, ale także reguła jednej definicji wymienia rodzaje rzeczy, których dotyczy, a typedefs nie jest jedną z nich. Powtórzenie byłoby dozwolone w C ++ pod ODR, tak jak jest sformułowane, nawet jeśli typedef byłby definicją. Wydaje się niepotrzebnie wybredny.
Steve Jessop,

... ale zgaduję, że ta lista w ODR faktycznie zawiera wszystkie rzeczy, których można mieć definicje. Jeśli tak, to lista jest zbędna i jest po prostu pomocna.
Steve Jessop,

Co mówi definicja ODR standardu na temat definicji klas? Oni muszą być powtarzane.
sbi

2
@sbi: ODR mówi „(1) Żadna jednostka tłumacząca nie może zawierać więcej niż jednej definicji dowolnego… typu klasy” i „(5) W programie może być więcej niż jedna definicja typu klasy… każda definicja pojawia się w innej jednostce tłumaczenia ”, a następnie dodatkowe wymagania, które sprowadzają się do„ definicji są takie same ”.
Steve Jessop,

17

Z wiki.answers.com:

Termin deklaracja oznacza (w C), że informujesz kompilator o typie, rozmiarze, aw przypadku deklaracji funkcji, typie i rozmiarze jej parametrów dowolnej zmiennej lub typu lub funkcji zdefiniowanej przez użytkownika w twoim programie. W deklaracji nie ma miejsca w pamięci dla żadnej zmiennej. Jednak kompilator wie, ile miejsca zarezerwować, na wypadek utworzenia zmiennej tego typu.

na przykład następujące są wszystkie deklaracje:

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

Z drugiej strony definicja oznacza, że ​​oprócz wszystkich rzeczy, które robi deklaracja, miejsce jest również zarezerwowane w pamięci. Możesz powiedzieć „DEFINICJA = DEKLARACJA + REZERWACJA PRZESTRZENI” poniżej to przykłady definicji:

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

patrz odpowiedzi .


3
To też jest złe (choć znacznie bliższe niż inne): struct foo {};to definicja , a nie deklaracja. Deklaracja foobyłaby struct foo;. Na tej podstawie kompilator nie wie, ile miejsca zarezerwować dla fooobiektów.
sbi

1
@Marcin: sbi mówi, że „kompilator wie, ile miejsca do zarezerwowania na wypadek utworzenia zmiennej tego typu” nie zawsze jest prawdziwe. struct foo;jest deklaracją, ale nie informuje kompilatora o wielkości foo. Dodałbym, że struct _tagExample { int a; int b; };to definicja. Dlatego w tym kontekście mylące jest nazywanie tego deklaracją. Oczywiście jest jedna, ponieważ wszystkie definicje są deklaracjami, ale wydaje się, że sugerujesz, że nie jest to definicja. Jest to definicja _tagExample.
Steve Jessop,

1
@Marcin Gil: Co oznacza, że ​​wiki „Odpowiedzi” nie zawsze są dokładne. Muszę tutaj głosować za wprowadzanie w błąd.
David Thornley,

1
Dowiadujemy się, że to, co cytowane adatapost jest prawdą, ale tak naprawdę (IMO) tak naprawdę nie odpowiada na pytanie. To, co zacytował Marcin, jest fałszywe. Przytaczanie standardów jest prawdą i odpowiada na pytanie, ale bardzo trudno jest nad tym zapanować.
Steve Jessop,

1
@David Thornley - nie ma problemu :) Na tym właśnie polega ta strona. Wybieramy i weryfikujemy informacje.
Marcin Gil

13

Aktualizacja C ++ 11

Ponieważ nie widzę odpowiedzi dotyczącej C ++ 11, oto jedna.

Deklaracja jest definicją, chyba że deklaruje a / n:

  • nieprzezroczysty enum - enum X : int;
  • parametr szablonu - T intemplate<typename T> class MyArray;
  • Zgłoszenie parametr - x i y wint add(int x, int y);
  • deklaracja aliasu - using IntVector = std::vector<int>;
  • deklaracja statyczna static_assert(sizeof(int) == 4, "Yikes!")
  • deklaracja atrybutu (zdefiniowana w implementacji)
  • pusta deklaracja ;

Dodatkowe klauzule odziedziczone po C ++ 03 z powyższej listy:

  • deklaracja funkcji - dodać wint add(int x, int y);
  • specyfikator zewnętrzny zawierający deklarację lub specyfikator powiązania - extern int a;lubextern "C" { ... };
  • element danych statycznych w klasie - x inclass C { static int x; };
  • deklaracja klasy / struktury - struct Point;
  • deklaracja typedef - typedef int Int;
  • za pomocą deklaracji - using std::cout;
  • za pomocą dyrektywy - using namespace NS;

Deklaracja szablonu jest deklaracją. Deklaracja szablonu jest również definicją, jeśli jej deklaracja definiuje funkcję, klasę lub element danych statycznych.

Przykłady ze standardu, który odróżnia deklarację od definicji, które okazały się pomocne w zrozumieniu niuansów między nimi:

// 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

Definicja:

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

Definicja kojarzy zmienną z typem i przydziela pamięć, podczas gdy deklaracja tylko określa typ, ale nie przydziela pamięci. Deklaracja jest bardziej przydatna, gdy chcesz odwołać się do zmiennej przed definicją.

* Nie myl definicji z inicjalizacją. Oba są różne, inicjalizacja nadaje wartość zmiennej. Zobacz powyższy przykład.

Poniżej podano kilka przykładów definicji.

int a;
float b;
double c;

Teraz deklaracja funkcji:

int fun(int a,int b); 

Zwróć uwagę na średnik na końcu funkcji, więc jest to tylko deklaracja. Kompilator wie, że gdzieś w programie funkcja ta zostanie zdefiniowana za pomocą tego prototypu. Teraz, jeśli kompilator otrzyma funkcję, należy wywołać coś takiego

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

Kompilator zgłosi błąd informujący, że nie ma takiej funkcji. Ponieważ nie ma żadnego prototypu dla tej funkcji.

Zwróć uwagę na różnicę między dwoma programami.

Program 1

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

W tym zadeklarowana i zdefiniowana jest również funkcja drukowania. Ponieważ wywołanie funkcji przychodzi po definicji. Teraz zobacz następny program.

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

Jest to niezbędne, ponieważ wywołanie funkcji poprzedza definicję, więc kompilator musi wiedzieć, czy istnieje taka funkcja. Dlatego deklarujemy funkcję, która poinformuje kompilator.

Definicja:

Ta część definiowania funkcji nazywa się Definicja. Mówi, co robić wewnątrz funkcji.

void print(int a)
{
    printf("%d",a);
}

2
int a; //declaration; a=10; //definitionTo jest całkowicie błędne. Kiedy mówimy o obiektach automatycznego czasu przechowywania (obiekty zadeklarowane w definicji funkcji, które nie są zadeklarowane innym specyfikatorem klasy pamięci, takim jak extern), są to zawsze definicje.
Joey Pabalinas,

Główną różnicą do uchwycenia jest to, że deklaracja mówi „coś istnieje gdzieś, który ma te cechy (typ itp.)”, Podczas gdy definicja mówi „deklaruję coś z tymi cechami, a także tworzę tutaj instancję jako dobrze." Ponieważ nie można przesyłać dalej takich deklaracji obiektów automatycznego czasu przechowywania, zawsze będą to definicje.
Joey Pabalinas,

Z wyjątkiem może niektórych dziwnych typowych przypadków narożnych, o których zawsze zapominam, ogólna zasada jest taka, że wszystkie definicje są deklaracjami. Pomyśl o tym; gdy tworzysz coś, musisz też poinformować kompilator, że to coś istnieje i jakie są jego cechy?
Joey Pabalinas,

Zaktualizowałem odpowiedź zgodnie z pierwszym komentarzem. jednak nie zgadzam się z tym komentarzem „gdy coś tworzysz, musisz także poinformować kompilator, że coś takiego istnieje”. Podczas tworzenia instancji nie zawsze określamy typ lhs. Np .: a = 10. Nie określamy żadnych „cech” tutaj.
SRIDHARAN

4

definicja oznacza zapisaną rzeczywistą funkcję, a deklaracja oznacza prostą funkcję deklarującą np

void  myfunction(); //this is simple declaration

i

void myfunction()
{
 some statement;    
}

to jest definicja funkcji myfunction


1
A co z typami i obiektami?
sbi

4

Praktyczna zasada:

  • Deklaracja informuje kompilator, jak interpretować dane zmiennej w pamięci. Jest to potrzebne przy każdym dostępie.

  • Definicja rezerwuje pamięć, aby zmienna istniejących. To musi się zdarzyć dokładnie raz przed pierwszym dostępem.


2
Dotyczy to tylko obiektów. Co z typami i funkcjami?
Lekkość ściga się na orbicie

4

Aby zrozumieć rzeczowniki, najpierw skupmy się na czasownikach.

deklarować - ogłaszać oficjalnie; głosić

Zdefiniuj - aby pokazać lub opisać (ktoś lub coś) jasno i całkowicie

Więc kiedy coś deklarujesz, po prostu mówisz, co to jest .

// declaration
int sum(int, int);

Ta linia deklaruje wywołaną funkcję C, sumktóra pobiera dwa argumenty typu inti zwraca an int. Jednak nie możesz go jeszcze użyć.

Kiedy podajesz, jak to naprawdę działa , to jest to jego definicja.

// definition
int sum(int x, int y)
{
    return x + y;
}

3

Aby zrozumieć różnicę między deklaracją a definicją, musimy zobaczyć kod asemblera:

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)

a to tylko definicja:

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)

Jak widać nic się nie zmienia.

Deklaracja różni się od definicji, ponieważ zawiera informacje używane tylko przez kompilator. Na przykład uint8_t mówi kompilatorowi, aby używał funkcji asm movb.

Zobaczyć, że:

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

Deklaracja nie ma równoważnej instrukcji, ponieważ nie można jej wykonać.

Ponadto deklaracja informuje kompilator o zakresie zmiennej.

Można powiedzieć, że deklaracja jest informacją używaną przez kompilator do ustalenia poprawnego użycia zmiennej i czasu, przez jaki część pamięci należy do określonej zmiennej.


2

Czy nie można powiedzieć w sposób najbardziej ogólny, że deklaracja jest identyfikatorem, w którym pamięć nie jest przydzielana, a definicja faktycznie alokuje pamięć od zadeklarowanego identyfikatora?

Jedna interesująca myśl - szablon nie może przydzielić pamięci, dopóki klasa lub funkcja nie zostaną połączone z informacjami o typie. Czy identyfikator szablonu jest deklaracją czy definicją? Powinna to być deklaracja, ponieważ nie przydzielono pamięci, a Ty po prostu „prototypujesz” klasę lub funkcję szablonu.


1
Twoja definicja nie jest sama w sobie niepoprawna, ale „definicja pamięci” zawsze wydaje się niezręczna, jeśli chodzi o definicje funkcji. Jeśli chodzi o szablony: template<class T> struct foo;jest to deklaracja szablonu , podobnie jak to template<class T> void f();. Definicje szablonów odzwierciedlają definicje klas / funkcji w ten sam sposób. (Pamiętaj, że nazwa szablonu nie jest nazwą typu ani funkcji . Jednym z miejsc, w których można to zobaczyć, jest to, że nie można przekazać szablonu jako parametru typu innego szablonu. Jeśli chcesz przekazać szablony zamiast typów, potrzebujesz parametrów szablonu szablonu. )
sbi

Zgodzono się, że „definicja pamięci” jest niewygodna, szczególnie w odniesieniu do definicji funkcji. Deklaracja to int foo (), a definicja to int foo () {// trochę kodu tutaj ..}. Zazwyczaj muszę zawinąć mój mały mózg w znane mi pojęcia - „przechowywanie” jest jednym z takich sposobów, aby zachować to dla mnie przynajmniej ... :)

2

Znajdź podobne odpowiedzi tutaj: Wywiad Pytania techniczne w C .

Deklaracja stanowi nazwę do programu; definicji zapewnia unikalny opis jednostki (na przykład typu, przykład i) w funkcji programu. Deklaracje mogą się powtarzać w danym zakresie, wprowadza nazwę w danym zakresie.

Deklaracja jest definicją, chyba że:

  • Deklaracja deklaruje funkcję bez określania jej treści,
  • Deklaracja zawiera zewnętrzny specyfikator i nie zawiera inicjalizatora ani treści funkcji,
  • Deklaracja to deklaracja członka klasy danych statycznych bez definicji klasy,
  • Deklaracja to definicja nazwy klasy,

Definicja jest deklaracją, chyba że:

  • Definicja definiuje element danych klasy statycznej,
  • Definicja definiuje nieliniową funkcję członka.

1

To zabrzmi naprawdę kiepsko, ale to najlepszy sposób, w jaki udało mi się zachować proste warunki w mojej głowie:

Deklaracja: Obraz Thomas Jefferson wygłasza przemówienie ... „OŚWIADCZAM, ŻE TO GŁOWIE ISTNIEJE W KODZIE ŹRÓDŁA !!!”

Definicja: wyobraź sobie słownik, szukasz Foo i co to właściwie znaczy.


1

Deklaracja przedstawia kompilatorowi nazwę symbolu. Definicja to deklaracja, która przydziela miejsce dla symbolu.

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

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

1

Zgodnie z podręcznikiem biblioteki GNU C ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )

W języku C deklaracja dostarcza jedynie informacji o istnieniu funkcji lub zmiennej i podaje jej typ. W przypadku deklaracji funkcji można również podać informacje o typach jej argumentów. Celem deklaracji jest umożliwienie kompilatorowi prawidłowego przetwarzania odniesień do deklarowanych zmiennych i funkcji. Z drugiej strony definicja przydziela pamięć dla zmiennej lub mówi, co robi funkcja.


0

Pojęcie Deklaracja i definicja będzie stanowić pułapkę, gdy używasz zewnętrznej klasy pamięci, ponieważ twoja definicja będzie w innym miejscu i deklarujesz zmienną w lokalnym pliku kodu (stronie). Jedną różnicą między C i C ++ jest to, że w C deklaracje są wykonywane normalnie na początku funkcji lub strony kodowej. W C ++ tak nie jest. Możesz zadeklarować w wybranym przez siebie miejscu.


1
To myli deklarację z definicją i jest po prostu błędne.
sbi

0

Moim ulubionym przykładem jest „int Num = 5” tutaj twoja zmienna jest 1. zdefiniowana jako int 2. zadeklarowana jako Num i 3. utworzona instancja z wartością pięciu. My

  • Zdefiniuj typ obiektu, który może być wbudowany lub klasę lub strukturę.
  • Zadeklaruj nazwę obiektu, więc zadeklarowano wszystko, co zawiera nazwę, w tym Zmienne, Funtions itp.

Klasa lub struktura pozwala zmienić sposób definiowania obiektów, gdy zostaną później użyte. Na przykład

  • Można zadeklarować heterogeniczną zmienną lub tablicę, które nie są specjalnie zdefiniowane.
  • Używając przesunięcia w C ++, możesz zdefiniować obiekt, który nie ma zadeklarowanej nazwy.

Kiedy uczymy się programowania, te dwa terminy są często mylone, ponieważ często robimy oba jednocześnie.


Nie rozumiem, dlaczego tak wiele osób głosowało za odpowiedzią sbi. Głosowałem za odpowiedzią bjhend, która była dość dobra, zwięzła, dokładna i znacznie bardziej aktualna niż moja. Smutno mi było, że byłem pierwszą osobą, która to zrobiła od 4 lat.
Jason K.,

0

Etapy generowania wykonywalnego:

(1) preprocesor -> (2) tłumacz / kompilator -> (3) linker

W etapie 2 (tłumacz / kompilator) instrukcje deklaracji w naszym kodzie informują kompilator, że tych rzeczy będziemy używać w przyszłości, a definicję można znaleźć później:

tłumacz upewnij się, że: co to jest? oznacza deklarację

i (3) etap (linker) potrzebuje definicji, aby powiązać rzeczy

Linker upewnij się, że: gdzie jest co? oznacza definicję


0

W K&R (2. edycja) istnieje kilka bardzo wyraźnych definicji; pomaga umieścić je w jednym miejscu i czytać je jako jedno:

„Definicja” odnosi się do miejsca, w którym zmienna jest tworzona lub przypisywana pamięć; „deklaracja” odnosi się do miejsc, w których podano charakter zmiennej, ale nie przydzielono pamięci. [p. 33]

...

Ważne jest rozróżnienie między deklaracją zmiennej zewnętrznej a jej definicją . Deklaracja ogłasza właściwości zmiennej (przede wszystkim jej typ); definicja powoduje również odłożenie pamięci. Jeśli linie

int sp;
double val[MAXVAL]

pojawiają się poza jakąkolwiek funkcją, definiują zmienne zewnętrzne spi valpowodują odkładanie pamięci, a także służą jako deklaracja dla reszty tego pliku źródłowego.

Z drugiej strony linie

extern int sp;
extern double val[];

Oświadczam, dla pozostałej części pliku źródłowego, który spstanowi int, i że valjest doublearray (którego wielkość jest określona gdzie indziej), ale nie tworzyć zmienne lub magazynowania rezerw dla nich.

Musi istnieć tylko jedna definicja zmiennej zewnętrznej wśród wszystkich plików tworzących program źródłowy. ... Rozmiary tablic muszą być określone z definicją, ale są opcjonalne z externdeklaracją. [pp. 80–81]

...

Deklaracje określają interpretację każdego identyfikatora; niekoniecznie rezerwują pamięć związaną z identyfikatorem. Deklaracje, które rezerwują pamięć, nazywane są definicjami . [p. 210]


-1

Deklaracja oznacza podanie nazwy i typu zmiennej (w przypadku deklaracji zmiennej), np .:

int i;

lub podaj nazwę, typ zwracany i typ parametru (parametrów) funkcji bez treści (w przypadku deklaracji funkcji), np .:

int max(int, int);

podczas gdy definicja oznacza przypisanie wartości do zmiennej (w przypadku definicji zmiennej), np .:

i = 20;

lub dostarczenie / dodanie treści (funkcji) do funkcji nazywa się definicją funkcji, np .:

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

wiele deklaracji czasowych i definicji można wykonać razem jako:

int i=20;

i:

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

W powyższych przypadkach definiujemy i deklarujemy zmienne ii function max().


faktyczna średnia z definicji, czy przypisać wartość / treść do zmiennej / funkcji, podczas gdy deklaracja oznacza podać nazwę, typ do zmiennej / funkcji
Puneet Purohit,

Możesz zdefiniować coś bez przypisywania wartości.
Wyścigi lekkości na orbicie

1
Dokładnie tak:int x;
Lekkość ściga się na orbicie

jest to deklaracja zmiennej x, a nie jej zboczenie
Puneet Purohit 15.04.13

2
Nie, to jedno i drugie. Mylisz definicję z inicjalizacją.
Wyścigi lekkości na orbicie
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.