Подтвердить что ты не робот

Почему переменная не может быть определена дважды в 2 файлах в C

Почему я не могу иметь int a; в файлах 2 C. Я собираюсь объединить оба, чтобы сделать исполняемый файл. Я знаю по опыту, что не могу, но я хочу найти, где это говорит стандарт C99, и запечатать мое понимание.

Я читаю стандарт ISO C99 от http://www.open-std.org/jtc1/sc22/wg...docs/n1256.pdf. Он говорит на стр. 42:

6.2.2 Связи идентификаторов

1 Идентификатор, объявленный в разных области или в той же области больше, чем можно сделать так, чтобы ссылаться на то же самое объекта или функции посредством процесса, называемого linkage. Существует три вида связь: внешняя, внутренняя и ни одна.

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

3 Если объявление области видимости идентификатор объекта или функции содержит спецификацию класса хранения статический, идентификатор имеет внутренний связь.

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

5 Если объявление идентификатора для функции не имеет класса хранения специфика, определяется его связь точно так, как если бы оно было объявлено с спецификация класса хранения extern.If объявление идентификатора для объект имеет область действия и нет тип хранилища, его связь внешнее.

После прочтения это выглядит так: если я объявляю переменную типа say int a; в 2 исходных файлах. то оба имеют внешнюю связь в соответствии с правилом 5 и 4., а затем согласно правилу 2 оба должны ссылаться на один и тот же объект. Тогда почему компилятор создает проблему. Где в стандарте намекают, что мы не можем объявить это в двух исходных файлах, и это должно вызвать ошибку компиляции. Во-первых, где в стандарте говорится, что int a является определением, а затем там, где сказано, что два примера определений неприемлемы. Я знаю, что это не допускается из моего опыта, но мне было бы очень полезно, если бы я смог найти это в стандарте и запечатать свое понимание.

Выполните следующие выдержки из стандартного количества в сочетании с этим правилом? или я пропустил этот клей?:

В заявлении указывается интерпретация и атрибуты набора идентификаторов. Определение идентификатор является декларацией для этого определите, что: - для объекта, причины для хранения объект; Для функции включает тело функции; - для перечисления постоянное или typedef имя, является (только) объявление идентификатора.

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

Внешнее определение является внешней декларацией, которая также является определением функции (кроме встроенного определение) или объект. Если идентификатор, объявленный с помощью внешнего связь используется в выражении (кроме как часть операнда оператор sizeof, результатом которого является целочисленная константа), где-то в вся программа должна быть точно одно внешнее определение для идентифицирует эр; в противном случае не более одного.

Спасибо.

4b9b3361

Ответ 1

Думаю, вам нужно 6.9.2/2:

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

и 6.9/5:

Внешнее определение - это внешнее объявление, которое также является определением функции (кроме встроенного определения) или объекта. Если идентификатор, объявленный с внешним ссылка используется в выражении (кроме как часть операнда оператора sizeofрезультат которого является целой константой), где-то во всей программе должно быть точно одно внешнее определение для идентификатора; в противном случае должно быть не более одного.

В принципе, int a; является предварительным определением. Вы можете иметь несколько предварительных определений в одной единице перевода, но эффект такой же, как и одно непреднамеренное внешнее определение (например, что-то вроде int a = 0;). Наличие более одного определения объекта с внешней связью в программе является нарушением 6.9/5.

Обратите внимание, что это "общее расширение", позволяющее допускать более чем одно внешнее определение объекта, пока не будет инициализировано не более одного, и определения согласуются (см. J.5.11).