В чем разница между определением и декларацией?


858

Значение обоих ускользает от меня.


91
@Lasse: не правда. Определение и определяет, и объявляет ;-)
Стив Джессоп,

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

6
Тем не менее, это не повторяющийся вопрос, поскольку он задает вопрос о C / C ++, тогда как этот другой вопрос задают обо всех языках или вообще ни о одном. У него просто дубликаты ответов (поскольку в этом другом вопросе некоторые ответы предпочитали игнорировать все языки, кроме C и / или C ++).
Стив Джессоп

5
@DavidThornley Я использую этот трюк: определение дает более точное описание данной переменной или функции. Чтобы запомнить это, я вспоминаю, что середина слова «определение» имеет сходство со словом «тоньше». :)
Марко Леогранде

4
Удивительно, сколько дерьма есть по этому вопросу. Это просто показывает, насколько неправильно понимается этот язык, и как эти недоразумения регулярно распространяются . Это грустно, правда.
Гонки легкости на орбите

Ответы:


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 :: a и S :: b [...]
структура S; // объявляет S
- конец примера

Подводя итог: стандарт C ++ считает , struct x;чтобы быть декларацией и определением . (Другими словами, «предварительное объявление» является неправильным , поскольку в C ++ нет других форм объявлений классов.)struct x {};

Спасибо Литбу (Йоханнесу Шаубу), который раскопал настоящую главу и стих в одном из своих ответов.


2
@unknown: либо ваш компилятор не работает, либо вы неправильно скопировали код sbi. Например, 6.7.2 (2) в N1124: «Все объявления, которые ссылаются на один и тот же объект или функцию, должны иметь совместимый тип; в противном случае поведение не определено».
Стив Джессоп

4
@Brian: "extern int i;" говорит, что я где-то инт, не беспокойся об этом. "Int I;" означает, что я - int, и его адрес и область определены здесь.
Дэвид Торнли

12
@ Брайан: Ты не прав. extern int iэто объявление, так как оно просто вводит / указывает i. Вы можете иметь столько, extern int iсколько хотите в каждом модуле компиляции. int iОднако это определение. Он обозначает пространство для целого числа, которое должно быть в этом модуле перевода, и рекомендует компоновщику связать все ссылки iс этим объектом. Если у вас есть более или менее одно из этих определений, компоновщик будет жаловаться.
ВОО

4
@Brian int i;в файловой / глобальной области видимости или в области функций - это определение как в C, так и в C ++. В C, потому что он выделяет память, и в C ++, потому что у него нет спецификатора extern или спецификации связи. Это равносильно тому, что говорит sbi: в обоих случаях это объявление указывает объект, с которым должны быть связаны все ссылки на «i» в этой области.
Стив Джессоп

4
@unknown, будьте осторожны , вы не можете переобъявить член в классе сфере: struct A { double f(int, double); double f(int, double); };недействительный, конечно. Это разрешено в другом месте, хотя. Есть несколько мест , где вы можете объявить вещи, но не определяет, тоже: void f() { void g(); }действительно, но не следующее: void f() { void g() { } };. Что такое определение и какое объявление имеет тонкие правила, когда дело доходит до шаблонов - будьте осторожны! +1 за хороший ответ.
Йоханнес Шауб -

168

Из стандартного раздела 3.1 C ++:

А декларация вводит имена в ЕП или 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
Декларация предназначена для того, чтобы компилятор принял имя (чтобы сообщить компилятору, что имя допустимо, имя вводится с намерением, а не опечаткой). Определение - это то, где имя и его содержание связаны. Определение используется компоновщиком для привязки ссылки на имя к содержанию имени.
Gab 是 好人

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

декларация

Объявления сообщают компилятору, что программный элемент или имя существует. Объявление вводит одно или несколько имен в программу. Объявления могут встречаться в программе более одного раза. Следовательно, классы, структуры, перечисляемые типы и другие определяемые пользователем типы могут быть объявлены для каждой единицы компиляции.

Определение

Определения указывают, какой код или данные описывает имя. Имя должно быть объявлено до того, как оно может быть использовано.


Хм, разве вы не можете даже определить классы и перечисления в каждом модуле компиляции? По крайней мере, я помещаю определения классов в свои заголовки и включаю их во все. Er, class foo {}; является класс определение , не так ли?
ВОО

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-initializer». Не в типе возврата :(
Йоханнес Шауб -

1
@litb: он не виден до объявления, только использование идентификатора перенесено за объявление. Да, я знаю, эффект одинаков во многих случаях. Но не во всех случаях, поэтому я думаю, что мы должны использовать точное объяснение. - Ой, подожди. Это видно в аргументах по умолчанию? Ну, это, безусловно, наносит ущерб моему пониманию. Проклятье! <pouts>
sbi

22

Из стандарта С99 6,7 (5):

Объявление определяет интерпретацию и атрибуты набора идентификаторов. Определение идентификатора является декларацией для этого идентификатора , что:

  • для объекта вызывает сохранение хранилища для этого объекта;
  • для функции включает тело функции;
  • для константы перечисления или имени typedef является (единственным) объявлением идентификатора.

Из стандарта C ++, 3.1 (2):

Декларация является определением если только оно не объявляет функцию без указания тела функции, оно содержит спецификатор extern или спецификацию связи и не является ни инициализатором, ни телом функции, оно объявляет член статических данных в объявлении класса, это объявление имени класса, или это объявление typedef, объявление-использование или директива-использование.

Тогда есть несколько примеров.

Интересно (или нет, но я немного удивлен этим), typedef int myint;это определение в C99, но только объявление в C ++.


@onebyone: Что касается typedef, разве это не означает, что это можно повторить в C ++, но не в C99?
ВОО

Это то, что удивило меня, и в том, что касается одного переводчика, да, в этом есть разница. Но ясно, что определение типа может быть повторено в C99 в разных единицах перевода. C не имеет явного «правила одного определения», как C ++, поэтому правила, которые он имеет, просто позволяют это. C ++ решил изменить его на объявление, но также одно правило определения перечисляет, к каким вещам оно относится, и typedefs не является одним из них. Таким образом, повторы будут разрешены в C ++ под ODR, как это сформулировано, даже если определение типа является определением. Кажется излишне придирчивым.
Стив Джессоп

... но я предполагаю, что этот список в ODR фактически содержит список всех вещей, которые можно определить. Если это так, то список на самом деле является избыточным, и только для того, чтобы быть полезным.
Стив Джессоп

Что определение ODR в std говорит об определениях классов? Они должны быть повторены.
ВОО

2
@sbi: ODR говорит: «(1) Ни одна единица перевода не должна содержать более одного определения любого ... типа класса» и «(5) В программе может быть более одного определения типа класса ... при условии, что каждое определение появляется в отдельной единице перевода ", а затем некоторые дополнительные требования, которые равняются" определениям то же самое ".
Стив Джессоп

17

С wiki.answers.com:

Термин объявление означает (на языке C), что вы сообщаете компилятору о типе, размере и, в случае объявления функции, типе и размере ее параметров любой переменной, или определенного пользователем типа или функции в вашей программе. В случае объявления в памяти не зарезервировано ни одной переменной. Однако компилятор знает, сколько места нужно зарезервировать в случае создания переменной этого типа.

например, ниже приведены все объявления:

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объектов.
ВОО

1
@Marcin: sbi говорит, что «компилятор знает, сколько места нужно зарезервировать в случае создания переменной этого типа», это не всегда так. struct foo;это объявление, но оно не сообщает компилятору размер foo. Я бы добавил, что struct _tagExample { int a; int b; };это определение. Поэтому в этом контексте вводить в заблуждение называть это декларацией. Конечно, это одно, поскольку все определения являются декларациями, но вы, похоже, предполагаете, что это не определение. Это определение _tagExample.
Стив Джессоп

1
@Marcin Gil: Это означает, что вики «Ответы» не всегда точны. Я должен понизить голосование за дезинформацию здесь.
Дэвид Торнли

1
Мы узнаем, что то, что процитировал adatapost, верно, но не (IMO) действительно отвечает на вопрос. То, что процитировал Марцин, является ложным. Цитирование стандартов является верным и отвечает на вопрос, но очень трудно сделать голову или хвост.
Стив Джессоп

1
@ Дэвид Торнли - не проблема :) Это то, о чем этот сайт. Мы выбираем и проверяем информацию.
Марцин Гил

13

C ++ 11 Обновление

Поскольку я не вижу ответа, относящегося к C ++ 11, вот один.

Объявление является определением, если оно не объявляет / 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), это всегда определения.
Джои Пабалинас

Основное отличие, которое нужно понять, заключается в том, что в декларации говорится, что «где-то существует вещь, имеющая эти черты (тип и т. Д.)», Тогда как в определении говорится: «Я заявляю вещь с этими чертами, и я также создаю ее экземпляр как хорошо." Поскольку вы не можете пересылать объявленные объекты продолжительности автоматического хранения, они всегда будут определениями.
Джои Пабалинас

За исключением некоторых странных угловых случаев определения типа, о которых я всегда забываю, практическое правило гласит, что все определения являются объявлениями. Думаю об этом; когда вы что-то создаете, вам также нужно сообщить компилятору, что эта вещь существует и каковы ее особенности?
Джои Пабалинас,

Обновил ответ согласно вашему первому комментарию. однако я не согласен с этим комментарием «когда вы создаете экземпляр чего-либо, вам также нужно сообщить компилятору, что это существует». Мы не всегда указываем тип lhs при создании экземпляра. Пример: а = 10. Мы не указываем какие-либо "черты" здесь.
СРИДХАРАН

4

определение означает фактическую написанную функцию, а объявление означает простую функцию объявления, например, для

void  myfunction(); //this is simple declaration

а также

void myfunction()
{
 some statement;    
}

это определение функции myfunction


1
А как насчет типов и объектов?
2013 г.,

4

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

  • Декларация сообщает компилятор , как интерпретировать данные переменные в памяти. Это необходимо для каждого доступа.

  • Определение оставляет память , чтобы сделать переменную существующие. Это должно произойти ровно один раз перед первым доступом.


2
Это относится только к объектам. А как насчет типов и функций?
Гонки легкости на орбите

4

Чтобы понять существительные, давайте сначала сосредоточимся на глаголах.

объявить - объявить официально; Proclaim

определить - показать или описать (кого-то или что-то) ясно и полностью

Итак, когда вы заявляете что-то, вы просто говорите, что это такое .

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

Найти похожие ответы здесь: Технические вопросы интервью в C .

Декларация предоставляет имя к программе; определение обеспечивает однозначное описание объекта (например , типа, экземпляр, и функцию) в рамках программы. Объявления могут повторяться в заданной области, это вводит имя в данной области.

Объявление является определением, если:

  • Объявление объявляет функцию без указания ее тела,
  • Объявление содержит внешний спецификатор и не содержит инициализатор или тело функции,
  • Объявление - это объявление члена данных статического класса без определения класса,
  • Объявление - это определение имени класса,

Определение является декларацией, если:

  • Определение определяет член данных статического класса,
  • Определение определяет не встроенную функцию-член.

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 вы объявления обычно делаются в начале функции или кодовой страницы. В С ++ это не так. Вы можете заявить в любом месте по вашему выбору.


1
Это путает декларацию с определением и совершенно неверно.
СБИ

0

Мой любимый пример - "int Num = 5", здесь ваша переменная 1. определена как int 2. объявлена ​​как Num и 3. создана со значением пять. Мы

  • Определите тип объекта, который может быть встроенным или класс или структура.
  • Объявите имя объекта, чтобы было объявлено все, что имеет имя, включая переменные, функции и т. Д.

Класс или структура позволяет вам изменить способ определения объектов при их последующем использовании. Например

  • Можно объявить гетерогенную переменную или массив, которые специально не определены.
  • Используя смещение в C ++, вы можете определить объект, у которого нет объявленного имени.

Когда мы учимся программировать, эти два термина часто путаются, потому что мы часто делаем оба одновременно.


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

0

Этапы исполняемого поколения:

(1) препроцессор -> (2) переводчик / компилятор -> (3) компоновщик

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

переводчик удостоверится, что: что к чему? означает декларацию

и (3) стадия (линкер) нуждается в определении, чтобы связать вещи

Линкер убедился, что: где что? означает определение


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.