Значение обоих ускользает от меня.
Объявление вводит идентификатор и описывает его тип, будь то тип, объект или функция. Объявление , что компилятор нуждается, чтобы принимать ссылки на этот идентификатор. Это объявления:
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 и С++ разрешено следующее:
double f(int, double);
double f(int, double);
extern double f(int, double); // the same as the two above
extern double f(int, double);
Однако он должен быть определен ровно один раз. Если вы забыли определить что-то, что было объявлено и где-то указано, то компоновщик не знает, на что ссылаться ссылки и жалуется на недостающие символы. Если вы определяете что-то более одного раза, то компоновщик не знает, какое из определений ссылается на ссылки и жалуется на дублированные символы.
Поскольку дискуссия о том, что представляет собой объявление класса, или определение класса в С++, продолжает появляться (в ответах и комментариях к другим вопросам), здесь я вставляю цитату из стандарта С++.
В 3.1/2 С++ 03 говорит:
Объявление является определением, если оно [...] является объявлением имени класса [...].
3.1/3 дает несколько примеров. Среди них:
[Example: [...] struct S { int a; int b; }; // defines S, S::a, and S::b [...] struct S; // declares S —end example
Подводя итог: стандарт С++ рассматривает struct x;
как объявление и struct x {};
определение. (Другими словами, "форвардная декларация" является неправильным выражением, поскольку в С++ нет других форм объявлений классов.)
Благодаря litb (Johannes Schaub), который выкопал настоящую главу и стих в одном из своих ответов.
Из стандартного раздела С++ 3.1:
Объявление вводит имена в единицы перевода или имена редекларов, введенные предыдущими деклараций. Объявление определяет интерпретацию и атрибуты этих имен.
В следующем параграфе говорится (подчеркивание мое), что объявление является определением, если...
... он объявляет функцию без указания функций body
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 стандарта С++:
Никакая единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.
struct x {static int b = 3; };
?
b
не объявлено как const
См stackoverflow.com/a/3536513/1858225 и daniweb.com/software-development/cpp/threads/140739/... .
Декларация: "Где-то существует foo".
Определение: "... и вот оно!"
В С++ имеются интересные краевые случаи (некоторые из них тоже в 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".
В С++ при использовании шаблонов есть еще один край.
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.
Декларация
В объявлениях сообщается компилятору, что элемент или имя программы существует. декларация вводит один или несколько имена в программу. Объявления могут встречаются более одного раза в программе. Поэтому классы, структуры, перечислены типы и другие определяемые пользователем типы могут быть объявлены для каждая единица компиляции.
Определение
Определения определяют, какой код или данные имя описывает. Имя должно быть объявленный до его использования.
class foo {};
является определение класса, не так ли?
Из стандарта C99, 6.7 (5):
Объявление определяет интерпретацию и атрибуты набора идентификаторов. Определение идентификатора - это объявление для этого идентификатора, которое:
Из стандарта С++, 3.1 (2):
Объявление - это определение, если оно не объявляет функцию без указания тела функции, содержит спецификатор extern или спецификацию привязки, а также ни инициализатор, ни тело функции, он объявляет статический член данных в объявлении класса, это объявление имени класса, или это объявление typedef, служебная декларация или директива using.
Тогда есть несколько примеров.
Так интересно (или нет, но я немного удивлен этим), typedef int myint;
- это определение в C99, но только объявление в С++.
typedef
, разве это не значит, что его можно повторить в C ++, но не в C99?
Из 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;
см. Answers.
struct foo {};
это определение , а не декларация. Объявление foo
было бы struct foo;
, Исходя из этого, компилятор не знает, сколько места зарезервировать для объектов foo
.
Поскольку я не вижу ответа, относящегося к С++ 11, здесь.
Объявление - это определение, если оно не объявляет /n:
enum X : int;
template<typename T> class MyArray;
int add(int x, int y);
using IntVector = std::vector<int>;
static_assert(sizeof(int) == 4, "Yikes!")
;
Дополнительные предложения, унаследованные от С++ 03 в приведенном выше списке:
int add(int x, int y);
extern int a;
или extern "C" { ... };
class C { static int x; };
struct Point;
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
Декларация:
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);
}
Это важно, потому что вызов функции предшествует определению, поэтому компилятор должен знать, есть ли такая функция. Поэтому мы объявляем функцию, которая будет информировать компилятор.
Определение:
Эта часть определения функции называется определением. В нем говорится, что делать внутри функции.
void print(int a)
{
printf("%d",a);
}
Теперь с переменными.
int a; //declaration
a=10; //definition
Несколько раз декларация и определение сгруппированы в один оператор вроде этого.
int a=10;
int a; //declaration; a=10; //definition
Это совершенно неправильно. Когда речь идет об объектах длительности автоматического хранения (объекты, объявленные внутри определения функции, которые не объявлены с другим спецификатором класса хранения, например extern), это всегда определения.
определение означает, что фактическая функция написана и декларация означает простую функцию объявления например.
void myfunction(); //this is simple declaration
и
void myfunction()
{
some statement;
}
это определение функции myfunction
Общее правило:
Объявление сообщает компилятору, как интерпретировать переменные данные в памяти. Это необходимо для каждого доступа.
A определение резервирует память, чтобы сделать существующую переменную. Это должно произойти ровно один раз перед первым доступом.
Найти похожие ответы здесь: Технические вопросы для интервью в C
Объявление содержит имя программы; определение предоставляет уникальное описание объекта (например, типа, экземпляра и функции) внутри программы. Объявления могут быть повторены в заданной области, он вводит имя в заданной области.
Объявление - это определение, если
Определение - это объявление, если:
Не могли бы вы заявить в наиболее общих терминах, что объявление является идентификатором, в котором не распределено хранилище, и определение фактически распределяет память из объявленного идентификатора?
Одна интересная мысль - шаблон не может распределять память до тех пор, пока класс или функция не будут связаны с информацией о типе. Так является ли идентификатор шаблона декларацией или определением? Это должно быть объявление, так как не распределено хранилище, и вы просто "прототипируете" класс или функцию шаблона.
template<class T> struct foo;
это объявление шаблона, как и этот template<class T> void f();
, Определения шаблонов отражают определения классов / функций таким же образом. (Обратите внимание, что имя шаблона не является именем типа или функции . Это можно увидеть в одном месте, когда вы не можете передать шаблон в качестве параметра типа другого шаблона. Если вы хотите передавать шаблоны вместо типов, вам нужны параметры шаблона шаблона. )
Согласно руководству библиотеки GNU C (http://www.gnu.org/software/libc/manual/html_node/Header-Files.html)
В C декларация просто предоставляет информацию о существовании функции или переменной и дает ее тип. Для объявления функции может быть предоставлена информация о типах ее аргументов. Цель деклараций - дать возможность компилятору правильно обрабатывать ссылки на объявленные переменные и функции. Определение, с другой стороны, фактически распределяет память для переменной или говорит, что делает функция.
Чтобы понять существительные, сначала сосредоточьтесь на глаголах.
объявить - официально объявить; провозглашают
определить - показать или описать (кто-то или что-то) ясно и полностью
Итак, когда вы что-то объявляете, вы просто рассказываете, что это такое.
// declaration
int sum(int, int);
Эта строка объявляет функцию C, называемую sum
, которая принимает два аргумента типа int
и возвращает 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)
Объявление не имеет эквивалентной инструкции, потому что это не что-то, что нужно выполнить.
Кроме того, объявление объявляет компилятору область действия переменной.
Мы можем сказать, что объявление - это информация, используемая компилятором для установления правильного использования переменной и того, как долго некоторая память принадлежит определенной переменной.
Это будет звучать действительно дрянным, но это лучший способ, которым я мог держать слова прямо в моей голове:
Декларация: изображение Томаса Джефферсона, выступающего с речью... "Я НАСТОЯЩИМ ЗАЯВЛЯЮ, ЧТО ЭТО ЭТО ПРЕДУПРЕЖДЕН В ЭТОМ ИСТОЧНИКЕ КОДА!!!"
Определение: изобразите словарь, вы смотрите Foo и на что он на самом деле означает.
Декларация означает указание имени и типа переменной (в случае объявления переменной) например:
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;
}
В приведенных выше случаях мы определяем и объявляем переменную я и функцию max()
Как этапы компиляции
(1) для каждого процессора → (2) переводчик → (3) ассемблер → (4) компоновщик
перед тем, как перейти на (2) этап (переводчик/компилятор), заявления декларации в нашем коде, которые пытаются рассказать (2) о том, что эти вещи мы будем использовать в будущем, и вы можете найти определение позже, а это означает:
переводчик убедитесь, что: что есть? означает объявление
и (4) этап (линкер) нуждается в определении, чтобы связать вещи
Linker убедитесь, что: где и что? означает определение
Переменная объявлена , когда компилятор информирован о существовании переменной (и это ее тип); он не выделяет хранилище для переменной в этой точке.
Переменная определена, когда компилятор выделяет хранилище для переменной.
В объявлении представлено имя символа компилятору. Определение - это объявление, которое выделяет пространство для символа.
int f(int x); // function declaration (I know f exists)
int f(int x) { return 2*x; } // declaration and definition
Всякий раз, когда мы записываем функцию после основной функции, компилятор будет через ошибку, поскольку он не имеет представления о функции во время вызова функции. Если мы предоставим прототип объявления функции, то мы, компилятор, не будем искать определения.
int sum(int,int);
main()
{
int res = sum(10,20);
}
int sum(int n1,int n2)
{
return(n1+n2);
}
В приведенном выше примере первая строка называется объявлением функции.
int sum(int,int);
Объявление переменной
Всякий раз, когда мы записываем инструкцию объявления, память не будет выделена для переменной. Объявление переменной будет случайным образом определять местоположение памяти.
int ivar;
float fvar;
Переменная декларация Vs Определение Параметры дифференциации
а. Космическое резервирование:
Всякий раз, когда мы объявляем переменную, пространство не будет зарезервировано для переменной. Всякий раз, когда мы объявляем переменную, компилятор не будет искать другие данные, такие как определение переменной.
Декларация - удобный способ написания кода, в котором фактическая память не выделена.
struct book {
int pages;
float price;
char *bname;
};
В вышеуказанной декларации память не выделяется. Всякий раз, когда мы определяем переменную, тогда для переменной будет выделена память.
struct book b1;
В. Что он делает?
Моим любимым примером является "int Num = 5", здесь ваша переменная равна 1. определяется как int 2. объявляется как Num и 3. создается экземпляр со значением пять. Мы
Класс или структура позволяет вам изменить способ определения объектов, когда он будет использоваться позднее. Например
Когда мы изучаем программирование, эти два термина часто путают, потому что мы часто делаем оба одновременно.
Концепция декларации и определения будет представлять собой ловушку, если вы используете класс внешнего хранилища, потому что ваше определение будет находиться в каком-то другом месте, и вы объявляете переменную в вашем локальном файле кода (странице). Одна разница между C и С++ заключается в том, что в C вы декларации выполняются обычно в начале функции или кодовой страницы. В С++ это не так. Вы можете объявить в выбранном вами месте.
Разница между объявлением и определением с помощью функций: Оператор prototype для функции объявляет его, то есть сообщает компилятору о функции - ее имени, типе возвращаемого номера, числе и типе его параметров. Заголовок функции, за которым следует тело функции, определяет функцию - дающую подробную информацию о шагах для выполнения функции.
Исх.
код:
//Declare
int foo(int);
//Define
int foo(int){
...
}
С уважением к переменным: Для автоматических и регистровых переменных нет разницы между определением и декларацией. Процесс объявления автоматической или регистровой переменной определяет имя переменной и выделяет соответствующую память.
Однако для внешних переменных: Поскольку память для переменной должна быть назначена только один раз, чтобы гарантировать, что доступ к переменной всегда относится к одной и той же ячейке. все переменные должны быть определены один раз и только один раз.
Если внешняя переменная должна использоваться в файле, отличном от того, в котором он определен, необходим механизм для "подключения" такого использования с выделенной для него однозначно определенной внешней переменной. Этот процесс соединения ссылок одной и той же внешней переменной в разных файлах называется разрешением ссылок.
Он может быть определен и объявлен с помощью оператора объявления вне любой функции без спецификатора класса хранения. Такое объявление выделяет память для переменной. Оператор объявления также может использоваться для простого объявления имени переменной с помощью спецификатора класса extern storage в начале объявления. Такое объявление указывает, что переменная определена в другом месте, то есть память для этой переменной выделяется в другом файле. Таким образом, доступ к внешней переменной в файле, отличном от того, в котором он определен, возможен, если он объявлен с ключевым словом extern; не выделяется новая память. Такое объявление сообщает компилятору, что переменная определена в другом месте, а код скомпилирован с внешней переменной, оставленной неразрешенной. Ссылка на внешнюю переменную разрешена во время процесса компоновки.
Исх.
код
//file1.c
extern char stack[10];
extern int stkptr;
....
//file2.c
char stack[10];
int stkptr;
....
Эти объявления сообщают компилятору, что переменные stack [] и stkptr определены в другом месте, обычно в каком-то другом файле. Если ключевое слово extern было опущено, переменные будут считаться новыми, и для них будет выделена память. Помните, что доступ к одной и той же внешней переменной, определенной в другом файле, возможен только в том случае, если в объявлении используется ключевое слово extern.
В объявлении вводится имя в программу; определение предоставляет уникальное описание объекта (например, тип, экземпляр и функция). Объявления могут быть повторены в заданной области, он вводит имя в заданной области. Должно быть точно одно определение каждого объекта, функции или класса, используемых в программе на С++. Декларация является определением, если:
* it declares a function without specifying its body,
* it contains an extern specifier and no initializer or function body,
* it is the declaration of a static class data member without a class definition,
* it is a class name definition,
* it is a typedef declaration.
Определение - это объявление, если:
* it defines a static class data member,
* it defines a non-inline member function.