Вопрос

Смысл и того, и другого ускользает от меня.

Это было полезно?

Решение

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 (Johannes Schaub) который откопал саму главу и стих в одном из своих ответов.

Другие советы

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

  

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

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

... объявляет функцию без указания функции & # 8217; тело s:

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

  

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

Объявление: " Где-то существует foo. "

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

В 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>. Он сообщает компилятору: & Quot; если речь идет о создании экземпляра X<bool>::member, не создавайте экземпляр определения элемента из основного шаблона, а используйте определение, найденное в другом месте & Quot ;. Чтобы сделать это определение, вы должны предоставить инициализатор

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

Декларация

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

Определение

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

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

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

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

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

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

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

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

От wiki.answers.com:

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

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

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

Определение с другой стороны означает, что в дополнение ко всем вещам, которые делает объявление, пространство также резервируется в памяти. Вы можете сказать & Quot; DEFINITION = DECLARATION + SPACE RESERVATION & Quot; Ниже приведены примеры определения:

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

см. ответы .

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

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

Декларация - это определение если только он не объявляет a / n:

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

Дополнительные предложения, унаследованные от C ++ 03 приведенным выше списком:

  • объявление функции - Добавить в int add(int x, int y);
  • спецификатор extern, содержащий объявление или спецификатор связи - extern int a; или extern "C" { ... };
  • статический элемент данных в классе - x в 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

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

void  myfunction(); //this is simple declaration

и

void myfunction()
{
 some statement;    
}

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

Эмпирическое правило:

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

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

Декларация.

int a; // this declares the variable 'a' which is of type 'int'

Таким образом, объявление связывает переменную с типом.

Ниже приведены некоторые примеры объявления.

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

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

Определение:

Эта часть определения функции называется Definition. Он говорит, что делать внутри функции.

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

Теперь с переменными.

int a; //declaration
a=10; //definition 

Иногда объявление и определение группируются в одно утверждение, подобное этому.

int a=10;

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

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

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

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

// declaration
int sum(int, int);

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

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

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

Чтобы понять разницу между объявлением и определением, нам нужно увидеть код сборки:

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)

Декларация не имеет эквивалентной инструкции, потому что ее не нужно выполнять.

Кроме того, объявление сообщает компилятору область действия переменной.

Можно сказать, что объявление - это информация, используемая компилятором для установления правильного использования переменной и того, как долго некоторая память принадлежит определенной переменной.

Не могли бы вы в самых общих терминах заявить, что объявление - это идентификатор, в котором не выделяется хранилище, а определение фактически выделяет хранилище из объявленного идентификатора?

Одна интересная мысль - шаблон не может выделять память, пока класс или функция не связаны с информацией о типе. Так является ли идентификатор шаблона декларацией или определением? Это должно быть объявление, поскольку хранилище не выделено, а вы просто «создаете прототип» класса или функции шаблона.

Найдите похожие ответы здесь: Технические вопросы для собеседования на языке Си.

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

Декларация - это определение, если только:

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

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

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

Это прозвучит действительно банально, но это лучший способ, которым я смог запомнить термины:

Декларация:Представьте себе Томаса Джефферсона, произносящего речь..."НАСТОЯЩИМ Я ЗАЯВЛЯЮ, ЧТО ЭТОТ FOO СУЩЕСТВУЕТ В ЭТОМ ИСХОДНОМ КОДЕ !!!"

Определение:представьте себе словарь, вы ищете Foo и что это на самом деле означает.

Объявление представляет имя символа для компилятора. Определение - это объявление, которое выделяет место для символа.

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

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

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

В C объявление просто предоставляет информацию о существовании функции или переменной и указывает ее тип.Для объявления функции также может быть предоставлена информация о типах ее аргументов.Цель объявлений - позволить компилятору корректно обрабатывать ссылки на объявленные переменные и функции.Определение, с другой стороны, фактически выделяет память для переменной или говорит, что делает функция.

Объявление означает присвоение имени и типа переменной (в случае объявления переменной), например:

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().

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

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

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

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

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

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

Этапы генерации исполняемого файла:

  

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

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

  

переводчик должен убедиться, что: что к чему? означает объявление

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

  

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top