Декларация или определение в C - PullRequest
23 голосов
/ 22 января 2011

С Внешние переменные Wiki :

Если нет ни ключевого слова extern, ни значения инициализации, оператор может быть либо объявлением, либо определением.Компилятор должен проанализировать модули программы и принять решение.

Я не смог полностью понять значение этого утверждения относительно C. Например, подразумевает ли это, что:

int i;

не обязательно является декларацией (как я предполагал до сих пор), но также может быть определением (по определению определения и декларации на той же веб-странице, каламбуры не предусмотрены)?

В двух словах, приведенное выше утверждение: a.просто декларация или б.объявление + определение?

Ссылка: Переменная декларация и определение

Сводка полученных ответов:

                         Declaration    Definition    Tentative Definition   Initialized 
int i;   (inside a block)    Yes           Yes                No                No
int i=5; (inside a block)    Yes           Yes                No               Yes(to 5)
int i;   (otherwise)         Yes            No               Yes               Yes(to 0)
extern int i;                Yes            No                No                No


All definitions are declarations but not vice-versa.

Ответы [ 5 ]

15 голосов
/ 22 января 2011

Предполагая, что это находится в области видимости файла, это «предварительное определение».От 6.9.2 / 2 «Определения внешних объектов»:

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

Это означает, что в единице перевода будет также допустимо:

int i = 42;

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

Поскольку объявление находится в области видимости блока, стандарт гласит следующее (6.2.2 / 2 "Связиидентификаторы "):

Каждое объявление идентификатора без связи обозначает уникальный объект.

...

(параграф 6) Следующие идентификаторы не имеют связи: ... идентификатор области блока для объекта, объявленного без спецификатора класса хранения extern.

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

14 голосов
/ 22 января 2011

Стандарт С говорит, что

Определение идентификатора - это объявление для этого идентификатора , которое: для объекта приводит к резервированию хранилища для этого объекта (…)

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

int i;

не является декларацией. Это является декларацией, которая также является определением. Или это определение, следовательно, декларация.

4 голосов
/ 22 января 2011

В контексте переменных:

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

    extern int x;
    

    в глобальной области видимости означает: "где-то в коде есть переменная с именем x, которая имеет тип int и внешнюю связь. Объявление необходимо до того, как вы обратитесь к x. (То же самое относится и к объявления функций.)

  • Определение - это оператор, который создает экземпляр этой переменной. Итак:

    int x;
    

    в глобальной области видимости создает единственную переменную типа int с внешней связью. Поэтому, если вы поместите эту строку в заголовок, каждый модуль перевода, включая этот заголовок, попытается создать свою собственную копию x, что нежелательно - поэтому у нас есть объявления только в заголовочных файлах. То же самое относится и к функциям: если вы предоставите тело функции, это определение.

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

1 голос
/ 22 января 2011

Поскольку C использует термины:

«Определение» создает что-то (что занимает какую-то память).Это тоже что-то описывает.Это означает, что «определение» также является «объявлением».

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

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

1 голос
/ 22 января 2011

Из спецификации C99:

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

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

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