Znaczenie obu mi umyka.
Znaczenie obu mi umyka.
Odpowiedzi:
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.
extern int i
jest deklaracją, ponieważ po prostu wprowadza / określa i
. W extern int i
każdej jednostce kompilacyjnej możesz mieć tyle, ile chcesz. int i
jest jednak definicją. Oznacza miejsce na liczbę całkowitą w tej jednostce tłumaczeniowej i radzi linkerowi, aby powiązał wszystkie odniesienia i
z tym podmiotem. Jeśli masz więcej niż jedną z tych definicji, linker narzeka.
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.
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ź.
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 extern
sł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 typedef
lub 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.
struct x {static int b = 3; };
?
b
zostanie również zadeklarowana const
. Zobacz stackoverflow.com/a/3536513/1858225 i daniweb.com/software-development/cpp/threads/140739/... .
Deklaracja: „Gdzieś istnieje foo”.
Definicja: „... i oto jest!”
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.
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.
class foo {};
czy to definicja klasy , prawda?
Ze standardu C99 6,7 (5):
Deklaracja określa interpretację i atrybuty zestawu identyfikatorów. Definicja identyfikatora jest deklaracja dla tego identyfikatora, że:
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 ++.
typedef
, czy to nie znaczy, że można to powtórzyć w C ++, ale nie w C99?
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 .
struct foo {};
to definicja , a nie deklaracja. Deklaracja foo
byłaby struct foo;
. Na tej podstawie kompilator nie wie, ile miejsca zarezerwować dla foo
obiektów.
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.
Ponieważ nie widzę odpowiedzi dotyczącej C ++ 11, oto jedna.
Deklaracja jest definicją, chyba że deklaruje 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!")
;
Dodatkowe klauzule odziedziczone po C ++ 03 z powyższej listy:
int add(int x, int y);
extern int a;
lubextern "C" { ... };
class C { static int x; };
struct Point;
typedef int Int;
using std::cout;
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
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);
}
int a; //declaration; a=10; //definition
To 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.
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.
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, sum
która pobiera dwa argumenty typu int
i 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;
}
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.
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.
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. )
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:
Definicja jest deklaracją, chyba że:
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.
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.
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.
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
Klasa lub struktura pozwala zmienić sposób definiowania obiektów, gdy zostaną później użyte. Na przykład
Kiedy uczymy się programowania, te dwa terminy są często mylone, ponieważ często robimy oba jednocześnie.
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ę
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
sp
ival
powodują 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
sp
stanowiint
, i żeval
jestdouble
array (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
extern
deklaracją. [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]
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 i
i function max()
.
int x;