В чем разница между определением и декларацией?
Значение обоих ускользает от меня.
Ответы
Ответ 1
Объявление вводит идентификатор и описывает его тип, будь то тип, объект или функция. Объявление , что компилятор нуждается, чтобы принимать ссылки на этот идентификатор. Это объявления:
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), который выкопал настоящую главу и стих в одном из своих ответов.
Ответ 2
Из стандартного раздела 3.1 C++:
Объявление вводит имена в модуль перевода или заново объявляет имена, введенные предыдущими объявлениями. Объявление определяет толкование и атрибуты этих имен.
Следующий абзац гласит (выделение мое), что объявление является определением, если...
... он объявляет функцию без указания тела функции:
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++:
Ни одна единица перевода не должна содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.
Ответ 3
Декларация: "Где-то существует foo".
Определение: "... и вот оно!"
Ответ 4
В С++ имеются интересные краевые случаи (некоторые из них тоже в 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.
Ответ 5
Декларация
В объявлениях сообщается компилятору, что элемент или имя программы существует. декларация вводит один или несколько имена в программу. Объявления могут встречаются более одного раза в программе. Поэтому классы, структуры, перечислены типы и другие определяемые пользователем типы могут быть объявлены для каждая единица компиляции.
Определение
Определения определяют, какой код или данные имя описывает. Имя должно быть объявленный до его использования.
Ответ 6
Из стандарта C99, 6.7 (5):
Объявление определяет интерпретацию и атрибуты набора идентификаторов. Определение идентификатора - это объявление для этого идентификатора, которое:
- для объекта, заставляет хранилище зарезервировать для этого объекта;
- для функции включает тело функции;
- для константы перечисления или имени typedef, является (единственным) объявлением
Идентификатор.
Из стандарта С++, 3.1 (2):
Объявление - это определение, если оно не объявляет функцию без указания тела функции, содержит спецификатор extern или спецификацию привязки, а также ни инициализатор, ни тело функции, он объявляет статический член данных в объявлении класса, это объявление имени класса, или это объявление typedef, служебная декларация или директива using.
Тогда есть несколько примеров.
Так интересно (или нет, но я немного удивлен этим), typedef int myint;
- это определение в C99, но только объявление в С++.
Ответ 7
Из 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.
Ответ 8
Обновление С++ 11
Поскольку я не вижу ответа, относящегося к С++ 11, здесь.
Объявление - это определение, если оно не объявляет /n:
- opaque enum -
enum X : int;
- параметр шаблона - T в
template<typename T> class MyArray;
- объявление параметра - x и y в
int add(int x, int y);
- Объявление псевдонима -
using IntVector = std::vector<int>;
- Объявление static assert -
static_assert(sizeof(int) == 4, "Yikes!")
- объявление атрибута (определяется реализацией)
- пустое объявление
;
Дополнительные предложения, унаследованные от С++ 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
Ответ 9
определение означает, что фактическая функция написана и декларация означает простую функцию объявления
например.
void myfunction(); //this is simple declaration
и
void myfunction()
{
some statement;
}
это определение функции myfunction
Ответ 10
Общее правило:
-
Объявление сообщает компилятору, как интерпретировать переменные данные в памяти. Это необходимо для каждого доступа.
-
A определение резервирует память, чтобы сделать существующую переменную. Это должно произойти ровно один раз перед первым доступом.
Ответ 11
Чтобы понять существительные, сначала сосредоточьтесь на глаголах.
объявить -
официально объявить; провозглашают
определить -
показать или описать (кто-то или что-то) ясно и полностью
Итак, когда вы что-то объявляете, вы просто рассказываете, что это такое.
// declaration
int sum(int, int);
Эта строка объявляет функцию C, называемую sum
, которая принимает два аргумента типа int
и возвращает int
. Однако вы еще не можете его использовать.
Когда вы указываете, как это работает, это определение.
// definition
int sum(int x, int y)
{
return x + y;
}
Ответ 12
Декларация:
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;
Ответ 13
Чтобы понять разницу между объявлением и определением, нам нужно увидеть код сборки:
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 <[email protected]>
def=5; | movb $0x5,-0x45(%rbp)
Объявление не имеет эквивалентной инструкции, потому что это не что-то, что нужно выполнить.
Кроме того, объявление объявляет компилятору область действия переменной.
Мы можем сказать, что объявление - это информация, используемая компилятором для установления правильного использования переменной и того, как долго некоторая память принадлежит определенной переменной.
Ответ 14
Не могли бы вы заявить в наиболее общих терминах, что объявление является идентификатором, в котором не распределено хранилище, и определение фактически распределяет память из объявленного идентификатора?
Одна интересная мысль - шаблон не может распределять память до тех пор, пока класс или функция не будут связаны с информацией о типе. Так является ли идентификатор шаблона декларацией или определением? Это должно быть объявление, так как не распределено хранилище, и вы просто "прототипируете" класс или функцию шаблона.
Ответ 15
Найти похожие ответы здесь: Технические вопросы интервью в C.
Объявление предоставляет имя для программы; определение обеспечивает уникальное описание объекта (например, типа, экземпляра и функции) в программе. Объявления могут повторяться в заданной области, это вводит имя в заданной области.
Объявление является определением, если:
- Объявление объявляет функцию без указания ее тела,
- Объявление содержит внешний спецификатор и не содержит инициализатор или тело функции,
- Объявление - это объявление члена данных статического класса без определения класса,
- Объявление - это определение имени класса,
Определение является декларацией, если:
- Определение определяет член данных статического класса,
- Определение определяет не встроенную функцию-член.
Ответ 16
Это будет звучать действительно дрянным, но это лучший способ, которым я мог держать слова прямо в моей голове:
Декларация: изображение Томаса Джефферсона, выступающего с речью... "Я НАСТОЯЩИМ ЗАЯВЛЯЮ, ЧТО ЭТО ЭТО ПРЕДУПРЕЖДЕН В ЭТОМ ИСТОЧНИКЕ КОДА!!!"
Определение: изобразите словарь, вы смотрите Foo и на что он на самом деле означает.
Ответ 17
В объявлении представлено имя символа компилятору. Определение - это объявление, которое выделяет пространство для символа.
int f(int x); // function declaration (I know f exists)
int f(int x) { return 2*x; } // declaration and definition
Ответ 18
Согласно руководству библиотеки GNU C (http://www.gnu.org/software/libc/manual/html_node/Header-Files.html)
В C декларация просто предоставляет информацию о существовании функции или переменной и дает ее тип. Для объявления функции может быть предоставлена информация о типах ее аргументов. Цель деклараций - дать возможность компилятору правильно обрабатывать ссылки на объявленные переменные и функции. Определение, с другой стороны, фактически распределяет память для переменной или говорит, что делает функция.
Ответ 19
В объявлении вводится имя в программу; определение предоставляет уникальное описание объекта (например, тип, экземпляр и функция). Объявления могут быть повторены в заданной области, он вводит имя в заданной области. Должно быть точно одно определение каждого объекта, функции или класса, используемых в программе на С++.
Декларация является определением, если:
* 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.
Ответ 20
Разница между объявлением и определением с помощью функций:
Оператор 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.
Ответ 21
Объявление означает присвоение имени и типа переменной (в случае объявления переменной), например:
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()
.
Ответ 22
Концепция декларации и определения будет представлять собой ловушку, если вы используете класс внешнего хранилища, потому что ваше определение будет находиться в каком-то другом месте, и вы объявляете переменную в вашем локальном файле кода (странице). Одна разница между C и С++ заключается в том, что в C вы декларации выполняются обычно в начале функции или кодовой страницы. В С++ это не так. Вы можете объявить в выбранном вами месте.
Ответ 23
Моим любимым примером является "int Num = 5", здесь ваша переменная равна 1. определяется как int 2. объявляется как Num и 3. создается экземпляр со значением пять. Мы
- Определите тип объекта, который может быть встроен, или класс или структура.
- Объявить имя объекта, поэтому было объявлено что-либо с именем, которое включает переменные, Funtions и т.д.
Класс или структура позволяет вам изменить способ определения объектов, когда он будет использоваться позднее. Например
- Можно объявить гетерогенную переменную или массив, которые конкретно не определены.
- Используя смещение в С++, вы можете определить объект, который не имеет объявленного имени.
Когда мы изучаем программирование, эти два термина часто путают, потому что мы часто делаем оба одновременно.
Ответ 24
Всякий раз, когда мы записываем функцию после основной функции, компилятор будет через ошибку, поскольку он не имеет представления о функции во время вызова функции. Если мы предоставим прототип объявления функции, то мы, компилятор, не будем искать определения.
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;
В. Что он делает?
- Декларация идентифицирует тип данных идентификатора.
- Определение переменной присваивает ей значение.
Ответ 25
Переменная объявлена , когда компилятор информирован о существовании переменной (и это ее тип); он не выделяет хранилище для переменной в этой точке.
Переменная определена, когда компилятор выделяет хранилище для переменной.
Ответ 26
Этапы исполняемого поколения:
(1) препроцессор → (2) переводчик/компилятор → (3) компоновщик
На этапе 2 (переводчик/компилятор) операторы объявления в нашем коде сообщают компилятору, что эти вещи мы будем использовать в будущем, и вы сможете найти определение позже, что означает:
переводчик удостоверится, что: что к чему? означает декларацию
и (3) этап (линкер) нуждается в определении, чтобы связать вещи
Линкер убедился, что: где что? означает определение
Ответ 27
Есть несколько очень четких определений, разбросанных по всему 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]