В чем разница между определением и декларацией? - PullRequest
800 голосов
/ 11 сентября 2009

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

Ответы [ 22 ]

810 голосов
/ 11 сентября 2009

A объявление вводит идентификатор и описывает его тип, будь то тип, объект или функция. Объявление , что нужно компилятору , чтобы принимать ссылки на этот идентификатор. Это декларации:

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

A определение фактически создает / реализует этот идентификатор. Это , что нужно компоновщику , чтобы связать ссылки с этими объектами. Это определения, соответствующие вышеуказанным декларациям:

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 затем приводит несколько примеров. Среди них:

[Example: [...]
struct S { int a; int b; }; // defines S, S::a, and S::b [...]
struct S; // declares S
—end example

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

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

163 голосов
/ 11 сентября 2009

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

A объявление вводит имена в единицу перевода или переименовывает имена, введенные предыдущими деклараций. Объявление определяет толкование и атрибуты этих имен.

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

... объявляет функцию без указания тела функции:

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

Ни одна единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.

126 голосов
/ 11 сентября 2009

Декларация: «Где-то существует foo.»

Определение: "... и вот оно!"

44 голосов
/ 11 сентября 2009

В 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.
32 голосов
/ 11 сентября 2009

Декларация

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

Определение

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

21 голосов
/ 11 сентября 2009

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

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

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

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

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

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

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

15 голосов
/ 11 сентября 2009

с 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; 

см. Ответы .

12 голосов
/ 26 июня 2013

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

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

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

  • непрозрачный enum - enum X : int;
  • параметр шаблона - T in template<typename T> class MyArray;
  • объявление параметров - x и y in 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" { ... };
  • член статических данных в классе - x in 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
4 голосов
/ 20 февраля 2018

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

объявить - официально объявить; провозглашать

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

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

// declaration
int sum(int, int);

Эта строка объявляет функцию C с именем sum, которая принимает два аргумента типа int и возвращает int. Тем не менее, вы еще не можете использовать его.

Когда вы указываете , как это на самом деле работает , это определение.

// definition
int sum(int x, int y)
{
    return x + y;
}
4 голосов
/ 17 апреля 2012

Правило большого пальца:

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

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

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