Почему переменная не может быть определена дважды в 2 файлах в C - PullRequest
22 голосов
/ 14 февраля 2011

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

Я читаю стандарт ISO C99 с http://www.open -std.org /ОТК1 / SC22 / WG ... Docs / n1256.pdf .На странице 42 говорится:

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

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

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

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

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

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

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

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

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

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

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

Спасибо.

1 Ответ

18 голосов
/ 14 февраля 2011

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

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

и 6,9 / 5:

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

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

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

...