У чому різниця між визначенням і декларацією?


857

Значення обох ухиляється від мене.


91
@Lasse: неправда. Дефініція і визначає, і декларує ;-)
Стів Джессоп

13
Чесно кажучи, у мене було багато проблем з навчанням, яке було, тому я не вважав імена очевидними. У мене не було проблем зі значеннями, лише те, які назви пов’язувати зі значеннями.
Девід Торнлі

6
Все-таки це не повторне запитання, оскільки це запитує про C / C ++, тоді як це інше запитання щодо всіх мов, або взагалі жодної. Він просто має повторювані відповіді (оскільки в цьому іншому запитанні деякі відповіді вибрали ігнорувати всю мову, крім C та / або C ++).
Стів Джессоп

5
@DavidThornley Я використовую цей трюк: а визначення дає більш тонке опис даної змінної або функції. Щоб запам'ятати це, я пригадую, що середина слова "визначення" має схожість зі словом "тонше". :)
Марко Леогранде

4
Дивовижно, скільки є лайно з цього питання. Просто показує, наскільки ця мова неправильно зрозуміла, і як ці непорозуміння регулярно поширюються . Це справді сумно.
светлота Гонки в Orbit

Відповіді:


858

Декларація вводить ідентифікатор і описує його тип, будь то тип, об'єкт або функція. Декларація - це те, що компілятору потрібно прийняти посилання на цей ідентифікатор. Це декларації:

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

Визначення фактично інстанцірует / реалізує цей ідентифікатор. Це те, що потрібен лінкеру , щоб зв’язати посилання на ці сутності. Це визначення, відповідні вищезазначеним деклараціям:

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

Ухвала може бути використано замість декларації.

Ідентифікатор можна оголошувати так часто, як вам потрібно. Таким чином, в C та 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);

Однак його потрібно визначити рівно один раз. Якщо ви забудете визначити щось, про що декларували і десь посилалися, то лінкер не знає, до чого посилатися на посилання та скаржиться на відсутні символи. Якщо ви визначаєте щось більше, ніж один раз, то лінкер не знає, до якого з визначень посилатися посилання та скаржиться на дублювані символи.


Оскільки дискусія про те, що таке декларація класу проти визначення класу в C ++, продовжує з'являтися (у відповідях та коментарях на інші запитання), я вставлю тут цитату зі стандарту C ++.
В 3,1 / 2, C ++ 03 говорить:

Декларація - це визначення, якщо це [...] є оголошенням імені класу [...].

3.1 / 3 наводить кілька прикладів. Серед них:

[Приклад: [...]
struct S {int a; int b; }; // визначає S, S :: а й S :: б [...]
struct S; // оголошує S
—Приклад

Підводячи підсумок: стандарт C ++ вважає , struct x;щоб бути декларацією і визначенням . (Іншими словами, "переадресація декларації" є неправильним , оскільки в C ++ немає інших форм оголошень класу.)struct x {};

Завдяки лібту (Йоханнесу Шаубу), який розкопав фактичну главу та вірш в одній із своїх відповідей.


2
@unknown: або ваш компілятор зламаний, ви неправильно скопіювали код sbi. Наприклад, 6.7.2 (2) в N1124: "Усі декларації, що відносяться до одного і того ж об'єкта або функції, повинні мати сумісний тип; інакше поведінка не визначена."
Steve Джессоп

4
@ Брайан: "ехЬегп INT I;" каже, що я десь інт, не хвилюйся про це. "int i;" означає, що я - це int, і тут визначається його адреса та сфера застосування.
Девід Торнлі

12
@Brian: Ви помиляєтесь. extern int iє декларацією, оскільки вона просто вводить / вказує i. У extern int iкожній одиниці компіляції може бути стільки, скільки ви хочете. int iоднак це визначення. Він позначає простір для цілого числа, що знаходиться в цій одиниці перекладу, і радить линкеру зв’язати всі посилання на iцю сутність. Якщо у вас є більш-менш точно одне з цих визначень, лінкер подасть скаргу.
sbi

4
@Brian int i;у файлі / глобальній області чи області функцій - це визначення як у C, так і в C ++. У C тому, що він виділяє сховище, а в C ++ тому, що у нього немає зовнішнього специфікатора або специфікації зв'язку. Вони складають одне і те ж, про що говорить sbi: в обох випадках ця декларація вказує об'єкт, до якого повинні бути пов'язані всі посилання на "i" у цій галузі.
Стів Джессоп,

4
@unknown, будьте обережні, що ви не можете передекларувати членів у межах класу : struct A { double f(int, double); double f(int, double); };невірно, звичайно. Це дозволено в інших місцях. Є кілька місць , де ви можете оголосити речі, але не визначає, теж: void f() { void g(); }дійсно, але не таке: void f() { void g() { } };. Що таке визначення і то , що декларація має тонкі правила , коли справа доходить до шаблонів - стережіться! +1 за хорошу відповідь , хоча.
Йоханнес Шауб - ліб

168

Із стандартного розділу C ++, розділ 3.1:

А декларація вводить імена в ЕП або redeclares імена , введені раніше декларацій. Декларація визначає тлумачення та ознаки цих назв.

У наступному абзаці зазначено (моє наголос), що декларація - це визначення, якщо ...

... він оголошує функцію, не вказуючи тіло функції:

void sqrt(double);  // declares sqrt

... він оголошує статичний член у визначенні класу:

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

... він оголошує ім'я класу:

class Y;

... воно містить externключове слово без ініціалізатора чи функції функції:

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

... або це typedefабо usingзаяву.

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

Тепер для великої причини, чому важливо зрозуміти різницю між декларацією та визначенням: Правило одного визначення . З розділу 3.2.1 стандарту C ++:

Жодна одиниця перекладу не містить більше одного визначення будь-якої змінної, функції, типу класу, типу перерахування чи шаблону.


"оголошує статичний член у визначенні класу" - Це вірно, навіть якщо статичний член ініціалізований, правильно? Чи можемо ми зробити приклад struct x {static int b = 3; };?
RJFalconer

@RJFalconer Ви маєте рацію; ініціалізація не обов'язково перетворює декларацію у визначення (всупереч тому, що можна очікувати; я, звичайно, вважаю це дивним). Ваша зміна прикладу насправді незаконна, якщо bтакож не задекларовано const. Див stackoverflow.com/a/3536513/1858225 і daniweb.com/software-development/cpp/threads/140739 / ... .
Кайл Странд

1
Це мені цікаво. Відповідно до вашої відповіді, схоже, що в C ++ декларація також є визначенням (за винятком), тоді як у стандарті C це словосполучення з іншого погляду (C99, розділ 6.7, Декларації): " Визначення ідентифікатора - це декларація для цього ідентифікатора, що: [з наступними критеріями для різних випадків] ". Думаю, різні способи поглянути на це. :)
Віктор Заманян

Декларація полягає в тому, що компілятор повинен прийняти ім'я (сказати компілятору, що ім'я є законним, ім'я вводиться з наміром, а не друком). Визначення - це місце, де ім'я та його вміст пов'язані. Визначення використовується лінкером для прив'язки посилання на ім'я до змісту імені.
Ґаб 是 好人

137

Декларація: "Десь там є фо".

Визначення: "... і ось воно!"


3
Декларація полягає в тому, що компілятор повинен прийняти ім'я (сказати компілятору, що ім'я є законним, ім'я вводиться з наміром, а не друком). Визначення - це місце, де ім'я та його вміст пов'язані. Визначення використовується лінкером для прив'язки посилання на ім'я до змісту імені.
Ґаб 是 好人

46

У C ++ є цікаві крайові випадки (деякі з них також і в C). Розглянемо

T t;

Це може бути визначення або декларація, залежно від типу 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".

У C ++ при використанні шаблонів є ще один крайній випадок.

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

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

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

Остання декларація не була визначенням. Це заява про явну спеціалізацію статичного члена X<bool>. Він повідомляє компілятору: "Якщо мова йде про інстанціювання X<bool>::member, то не інстанціюйте визначення члена з основного шаблону, а використовуйте визначення, знайдене в іншому місці". Щоб визначити це, вам потрібно надати ініціалізатор

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

35

Декларація

Декларації повідомляють компілятору про те, що існує програмний елемент або ім'я. Декларація вносить в програму одне або більше імен. Декларації в програмі можуть виникати не один раз. Тому класи, структури, перелічені типи та інші визначені користувачем типи можуть бути оголошені для кожної одиниці компіляції.

Визначення

Визначення вказують, який код або дані описує ім'я. Ім'я повинно бути оголошено, перш ніж воно може бути використане.


Гм, чи не так, ви навіть можете визначити класи та перерахунки у кожній одиниці компіляції? Принаймні, я кладу визначення класів у свої заголовки і включаю їх у всьому. Ер, class foo {}; це визначення класу , чи не так?
sbi

1
Так. Однак "клас foo;" є декларацією. Це повідомляє компілятору, що foo - це клас. "class foo {};" - це визначення. Він точно повідомляє компілятору, що таке клас foo.
Девід Торнлі

1
Виняток становлять імена членів класу, які можуть бути використані до їх оголошення.
Йоханнес Шауб - ліб

1
Так, це я мав на увазі. Отже, ви можете зробити наступне: struct foo {void b () {f (); } void f (); }, f видно, хоча ще не оголошено. Працюють і такі: struct foo {void b (int = bar ()); typedef int bar; };. Це видно перед його оголошенням у "всіх функціональних органах, аргументах за замовчуванням, конструкторі ctor-ініціалізаторів". Не в типі повернення :(
Йоханнес Шауб - ліб

1
@litb: Це не видно до його оголошення, лише використання ідентифікатора переміщено за декларацією. Так, я знаю, ефект однаковий для багатьох випадків. Але не для всіх випадків, тому я думаю, що ми повинні використовувати точне пояснення. - На жаль, зачекайте. Це видно в аргументах за замовчуванням? Ну, це, безумовно, сприймає моє розуміння. Чорт! <pouts>
sbi

22

Згідно зі стандартом C99, 6,7 (5):

Декларація вказує інтерпретацію та атрибути набору ідентифікаторів. Визначення ідентифікатора є декларацією для цього ідентифікатора , що:

  • для об'єкта викликає збереження сховища для цього об’єкта;
  • для функції, включає тіло функції;
  • для константи перерахування або імені typedef - це (єдине) оголошення ідентифікатора.

Згідно зі стандартом C ++, 3.1 (2):

Декларація - це визначення, якщо воно не оголошує функцію, не вказуючи тіло функції, воно не містить специфікатора extern або специфікації зв'язку і не є ініціалізатором, ані тіло функції, воно оголошує статичний член даних в декларації класу, це оголошення імені класу, або це декларація typedef, декларація з використанням або директива використання.

Тоді є кілька прикладів.

Настільки цікаво (чи ні, але я трохи здивований цим) typedef int myint;- це визначення в C99, але лише декларація в C ++.


@onebyone: Що стосується цього typedef, чи не означає це, що це може повторюватися в C ++, але не в C99?
sbi

Це мене здивувало, і що стосується однієї одиниці перекладу, так, є така різниця. Але ясно, що typedef може бути повторений у C99 в різних одиницях перекладу. У C немає явного "одного правила визначення", як C ++, тому правила, які він має, просто дозволяють. C ++ вирішив змінити його на декларацію, але також одне правило визначення містить список речей, до яких він застосовується, а typedefs не є одним із них. Таким чином, повтори дозволені в C ++ під ODR, як це написано, навіть якщо typedef був визначенням. Здається, зайве прискіпливе.
Стів Джессоп

... але я здогадуюсь, що у списку ODR насправді перераховані всі речі, про які можна визначити. Якщо так, то список насправді є зайвим, і він просто є корисним.
Стів Джессоп

Що визначення ODR STD говорить про визначення класів? Їх треба повторити.
sbi

2
@sbi: ODR говорить: "(1) Жодна одиниця перекладу не повинна містити більше одного визначення будь-якого ... типу класу" і "(5) У програмі може бути більше одного визначення типу класу ... за умови, що кожне визначення з'являється в різній одиниці перекладу ", а потім деякі додаткові вимоги, що означають" визначення однакові ".
Стів Джессоп

17

З wiki.answers.com:

Термін декларація означає (в С), що ви повідомляєте компілятору про тип, розмір, а в разі оголошення функції, тип і розмір його параметрів будь-якої змінної або визначений користувачем тип або функцію у вашій програмі. У пам'яті не залишається місця для жодної змінної у разі декларування. Однак компілятор знає, скільки місця потрібно резервувати, якщо буде створена змінна цього типу.

Наприклад, наведено всі декларації:

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

Визначення з іншого боку означає, що в доповненнях до всіх речей, які робить декларація, місце також зарезервоване в пам'яті. Ви можете сказати "ВИЗНАЧЕННЯ = ДЕКЛАРАЦІЯ + РЕЗЕРВАЦІЯ ПРОСТА" нижче: приклади визначення:

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

див. відповіді .


3
Це теж неправильно (хоча набагато ближче, ніж інші): struct foo {};це визначення , а не декларація. Декларація fooбуде struct foo;. З цього приводу компілятор не знає, скільки місця можна резервувати для fooоб’єктів.
sbi

1
@Marcin: sbi каже, що "компілятор знає, скільки місця для резервування, якщо буде створена змінна цього типу", не завжди відповідає дійсності. struct foo;є декларацією, але вона не вказує компілятору розміру foo. Я додам, що struct _tagExample { int a; int b; };це визначення. Тож у цьому контексті оманливо називати це декларацією. Звичайно, це одне, оскільки всі визначення є деклараціями, але ти, здається, припускаєш, що це не визначення. Це визначення _tagExample.
Стів Джессоп

1
@Marcin Gil: Це означає, що вікі "Відповіді" не завжди є точною. Я маю право виступати за дезінформацію тут.
Девід Торнлі

1
Ми дізнаємось, що те, що цитується адатапост, є правдою, але насправді не відповідає (ІМО). Те, що цитував Марцін, помилкове. Цитування стандартів відповідає дійсності і відповідає на питання, але це дуже важко зробити головою або хвостом.
Стів Джессоп

1
@David Thornley - не проблема :) Про це йдеться на цьому веб-сайті. Ми вибираємо та перевіряємо інформацію.
Marcin Gil

13

C ++ 11 Оновлення

Оскільки я не бачу відповіді, що стосується C ++ 11, ось одна.

Декларація - це визначення, якщо вона не оголошує a / n:

  • непрозорий перелік - enum X : int;
  • параметр шаблону - T вtemplate<typename T> class MyArray;
  • оголошення параметра - х і у вint add(int x, int y);
  • декларація про псевдонім - using IntVector = std::vector<int>;
  • статична заява про ствердження - static_assert(sizeof(int) == 4, "Yikes!")
  • декларація атрибута (визначено реалізацією)
  • порожня декларація ;

Додаткові пропозиції, успадковані від C ++ 03 вищезазначеним списком:

  • Оголошення функції - додати вint add(int x, int y);
  • зовнішній специфікатор, що містить декларацію або специфікатор зв'язку - extern int a;абоextern "C" { ... };
  • статичний член даних у класі - х вclass C { static int x; };
  • декларація класу / структури - struct Point;
  • декларація typedef - typedef int Int;
  • за допомогою декларації - using std::cout;
  • з використанням директиви - using namespace NS;

Шаблон-декларація - це декларація. Шаблон-декларація - це також визначення, якщо його декларація визначає функцію, клас або статичний член даних.

Приклади зі стандарту, який розрізняє декларацію та визначення, який я вважав корисним для розуміння нюансів між ними:

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

Визначення:

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

Визначення асоціює змінну з типом і розподіляє пам'ять, тоді як декларація просто вказує тип, але не виділяє пам'ять. Декларація є більш корисною, коли ви хочете віднести змінну до визначення.

* Не плутайте визначення з ініціалізацією. Обидва різні, ініціалізація надає значення змінній. Дивіться вищенаведений приклад.

Далі наведено кілька прикладів визначення.

int a;
float b;
double c;

Тепер декларація функції:

int fun(int a,int b); 

Зверніть увагу на крапку з комою в кінці функції, щоб сказати, що це лише декларація. Компілятор знає, що десь у програмі ця функція буде визначена з цим прототипом. Тепер, якщо компілятор отримує функцію, викликайте щось подібне

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

Компілятор видасть помилку, сказавши, що такої функції немає. Тому що у нього немає жодного прототипу для цієї функції.

Зверніть увагу на різницю між двома програмами.

Програма 1

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

У цьому функція друку оголошується і визначається також. Оскільки виклик функції надходить після визначення. Тепер дивіться наступну програму.

Програма 2

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

Це важливо, оскільки виклик функції передує визначенню, тому компілятор повинен знати, чи є така функція. Тож ми оголошуємо функцію, яка інформує компілятора.

Визначення:

Ця частина визначення функції називається визначення. Він говорить, що робити всередині функції.

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

2
int a; //declaration; a=10; //definitionЦе абсолютно неправильно. Коли ми говоримо про об'єкти тривалості автоматичного зберігання (об’єкти, оголошені всередині визначення функції, які не оголошені з іншим специфікатором класу зберігання, як extern), це завжди визначення.
Joey Pabalinas

Основна відмінність розуміння полягає в тому, що декларація говорить про те, що "десь існує десь, яка має ці риси (тип і т.д.)", тоді як дефініція говорить: "Я декларую річ із цими ознаками, і я також моментую це як добре." Оскільки ви не можете пересилати такі об'єкти автоматичної тривалості зберігання як такі, вони завжди будуть визначеннями.
Joey Pabalinas

За винятком, можливо, деяких дивних кутових випадків, про які я завжди забуваю, головне правило полягає в тому, що всі визначення - це декларації. Подумай над цим; коли ви щось створюєте, вам також потрібно сказати компілятору, що ця річ існує і які її риси є правильними?
Joey Pabalinas

Оновіть відповідь за вашим першим коментарем. однак я не згоден з цим коментарем "коли ви щось створюєте, ви також повинні сказати компілятору, що ця річ існує". Ми не завжди визначаємо тип lhs при інстанціюванні. Приклад: a = 10. Ми не вказуємо жодних "ознак" тут.
СРІДГАРАН

4

визначення означає фактичну функцію, записану, а декларація означає просту функцію оголошення, наприклад

void  myfunction(); //this is simple declaration

і

void myfunction()
{
 some statement;    
}

це визначення функції функції


1
А як щодо типів та об’єктів?
sbi

4

Практичне правило:

  • Декларація повідомляє компілятор , як інтерпретувати дані змінні в пам'яті. Це потрібно для кожного доступу.

  • Визначення залишає пам'ять , щоб зробити змінну існуючі. Це має відбутися рівно один раз до першого доступу.


2
Це справедливо лише для об'єктів. А як щодо типів та функцій?
Гонки легкості по орбіті

4

Щоб зрозуміти іменники, давайте спочатку зосередимося на дієсловах.

заявляти - оголошувати офіційно; проголошувати

визначити - показати або описати (когось чи щось) чітко та повністю

Отже, коли декларуєте щось, ви просто повідомте, що це таке .

// declaration
int sum(int, int);

Цей рядок оголошує функцію C, яка називається, sumяка бере два аргументи типу intта повертаєint . Однак ви поки не можете його використовувати.

Коли ви надаєте, як це насправді працює , це визначення цього.

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

3

Щоб зрозуміти різницю між декларацією та визначенням, нам потрібно переглянути код складання:

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)

і це лише визначення:

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)

Як ви бачите, нічого не зміниться.

Декларація відрізняється від визначення, оскільки вона дає інформацію, яку використовує лише компілятор. Наприклад, uint8_t скажіть компілятору використовувати функцію asm movb.

Бачиш це:

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

Декларація не має еквівалентної інструкції, тому що вона нічого не повинна бути виконана.

Крім того, декларація повідомляє компілятору область застосування змінної.

Можна сказати, що декларація - це інформація, яка використовується компілятором для встановлення правильного використання змінної та за те, як довго деяка пам'ять належить певній змінній.


2

Не могли б ви сказати на найбільш загальних можливих термінах, що декларація - це ідентифікатор, в якому не виділяється сховище, а визначення фактично виділяє сховище з оголошеного ідентифікатора?

Одна цікава думка - шаблон не може виділити сховище, поки клас чи функція не пов'язані з інформацією про тип. Так ідентифікатор шаблону є декларацією чи визначенням? Це має бути декларація, оскільки не виділено місця для зберігання даних, і ви просто "прототипуєте" шаблон шаблону або функції.


1
Ваше визначення не є помилковим, але "визначення сховища" завжди здається незручним, коли мова йде про визначення функцій. Щодо шаблонів: Це деклараціяtemplate<class T> struct foo; шаблону , і це так . Визначення дзеркальних визначень шаблонів / функцій шаблону аналогічно. (Зверніть увагу, що назва шаблону не є ім'ям типу або функції . Одне місце, де ви можете бачити це, коли ви не можете передати шаблон як параметр типу іншого шаблону. Якщо ви хочете передавати шаблони замість типів, вам потрібні параметри шаблону шаблону. )template<class T> void f();
sbi

Погодилися, що "визначення сховища" незручне, особливо щодо визначення функцій. Декларація - int foo (), а визначення - int foo () {// деякий код тут ..}. Мені зазвичай потрібно обернути мій маленький мозок поняттями, які мені знайомі - "зберігання" - це один із таких способів, щоб принаймні це було прямо мені ... :)

2

Знайдіть подібні відповіді тут: Питання технічного інтерв'ю в С .

Декларація надає ім'я до програми; визначення забезпечує однозначне опис об'єкта (наприклад , типу, екземпляр, і функцію) в рамках програми. Декларації можна повторити в заданому обсязі, воно вводить назву в задану область.

Декларація - це визначення, якщо:

  • Декларація оголошує функцію, не вказуючи її тіло,
  • Декларація містить зовнішній специфікатор і не містить ініціалізатора чи функції функції,
  • Декларація - це оголошення члена статичного класу без визначення класу,
  • Декларація - це визначення назви класу,

Визначення - це декларація, якщо:

  • Визначення визначає член даних статичного класу,
  • Визначення визначає функцію не вбудованого члена.

1

Це буде звучати насправді зухвало, але це найкращий спосіб, коли мені вдалося дотримати умови прямо в голові:

Декларація: Малюнок Томаса Джефферсона, який виступає з промовою ... "Я ТЕХНЯ ДЕКЛАРУЮТЬСЯ, ЩО ЦЕ ФОТО ІСНУЄ В ЦЬОМУ ДЖЕРЕЛАВІ КОДІ !!!"

Визначення: малюйте словник, ви шукаєте Foo і що він насправді означає.


1

Декларація представляє ім'я символу компілятору. Визначення - це декларація, яка виділяє простір для символу.

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

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

1

Відповідно до посібника з бібліотеки GNU C ( http://www.gnu.org/software/libc/manual/html_node/Header-Files.html )

В C декларація просто надає інформацію про те, що функція або змінна існує, і надає її тип. Для декларації функції також може бути надана інформація про типи її аргументів. Мета декларацій - дозволити компілятору правильно обробляти посилання на оголошені змінні та функції. Дефініція, з іншого боку, фактично виділяє сховище для змінної або говорить про те, що робить функція.


0

Концепція Декларації та Визначення створить підводний камінь, коли ви використовуєте клас зовнішнього зберігання, оскільки ваше визначення буде в якомусь іншому місці, і ви декларуєте змінну у вашому локальному файлі коду (сторінки). Однією з різниць між C і C ++ є те, що в C ви декларації робляться нормально на початку функції або кодової сторінки. У C ++ це не так. Ви можете декларувати в обраному вами місці.


1
Це плутає декларацію з визначенням і явно неправильно.
sbi

0

Мій улюблений приклад - "int Num = 5", тут ваша змінна значення 1. визначена як int 2. оголошена як Num і 3. instantiated зі значенням п'ять. Ми

  • Визначте тип об’єкта, який може бути вбудованим або класом або структурою.
  • Оголосіть назву об’єкта, так що все з ім’ям оголошено, що включає Змінні, Функції тощо.

Клас або структура дозволяє змінювати, як будуть визначені об'єкти при подальшому використанні. Наприклад

  • Можна оголосити гетерогенну змінну або масив, які конкретно не визначені.
  • Використовуючи зміщення в C ++, ви можете визначити об'єкт, який не має оголошеного імені.

Коли ми вивчаємо програмування, ці два терміни часто плутають, тому що ми часто робимо обидва одночасно.


Я не розумію, чому так багато людей підтримали відповідь sbi. Я відповів на відповідь bjhend, яка була досить хорошою, стислою, точною та набагато більш своєчасною, ніж моя. Мені було сумно бачити, що я був першою людиною, яка зробила це за 4 роки.
Джейсон К.

0

Етапи виконуваного покоління:

(1) попередній процесор -> (2) перекладач / компілятор -> (3) лінкер

На етапі 2 (перекладач / компілятор) заяви заяви в нашому коді повідомляють компілятору, що ці речі ми будемо використовувати в майбутньому, і ви можете знайти визначення пізніше, тобто:

перекладач переконайтесь, що: що таке? означає декларацію

та (3) етап (лінкер) потребує визначення для зв'язування речей

Linker переконайтесь, що: де що? означає визначення


0

Є декілька дуже чітких визначень, викладених у K&R (2-е видання); це допомагає розмістити їх в одному місці та прочитати як одне:

"Визначення" відноситься до місця, де створена змінна або призначена сховище; "декларація" відноситься до місць, де вказано характер змінної, але зберігання не виділено. [с. 33]

...

Важливо розрізняти декларацію зовнішньої змінної та її визначення . Декларація оголошує властивості змінної (насамперед її тип); Визначення також приводить до відміни пам’яті. Якщо лінії

int sp;
double val[MAXVAL]

з'являються поза будь-якою функцією, вони визначають зовнішні змінні spта valвикликають відкладення сховища, а також служать декларацією для решти цього вихідного файлу.

З іншого боку, лінії

extern int sp;
extern double val[];

оголосити для решти вихідного файлу, що spє intі valце doubleмасив (розмір якого визначено в іншому місці), але вони не створюють змінних і не резервують для них сховище.

Серед усіх файлів, що складають вихідну програму, повинно бути лише одне визначення зовнішньої змінної. ... Розміри масиву повинні бути вказані з визначенням, але необов'язкові зextern оголошенням. [с. 80-81]

...

Декларації визначають інтерпретацію, що надається кожному ідентифікатору; вони не обов'язково резервують сховище, пов'язане з ідентифікатором. Декларації, що резервують зберігання, називаються визначеннями . [с. 210]


-1

Декларація означає назву та тип змінної (у разі декларування змінної), наприклад:

int i;

або надати ім'я, тип повернення та параметр (и) типу функції без тіла (у разі оголошення функції), наприклад:

int max(int, int);

тоді як визначення означає присвоєння значення змінній (у випадку визначення змінної), наприклад:

i = 20;

або надати / додати тіло (функціональність) функції називається визначенням функції, наприклад:

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

багато часу декларація та визначення можуть бути зроблені разом як:

int i=20;

і:

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

У наведених вище випадках ми визначаємо та оголошуємо змінну iта function max().


фактичне середнє визначення, якщо призначити значення / тіло змінній / функції, тоді як декларація означає ім'я, введіть змінну / функцію
Puneet Purohit

Ви можете визначити щось, не присвоюючи йому значення.
Гонки легкості на орбіті


його декларація змінної x, а не її визначення
Puneet Purohit

2
Ні, це обоє. Ви плутаєте визначення з ініціалізацією.
Гонки легкості на орбіті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.