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

Каково обоснование предварительных определений в C?

Рассмотрим следующую программу. Это даст какие-либо ошибки компиляции?

#include <stdio.h>
int s=5;
int s;
int main(void)
{
     printf("%d",s);
}

На первый взгляд кажется, что компилятор даст переменную ошибку переопределения, но программа отлично действует в соответствии со стандартом C. (Смотрите демо-версию здесь http://ideone.com/Xyo5SY).

Предварительное определение - это любое объявление внешних данных, которое не имеет спецификатора класса хранения и не имеет инициализатора.

C99 6.9.2/2

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

Мой вопрос в том, что является обоснованием для разрешения предварительных определений? Есть ли использование этого в C? Почему C разрешает предварительные определения?

4b9b3361

Ответ 1

Предварительные определения были созданы как способ преодоления несовместимых моделей, существовавших до C89. Это описано в разделе Обоснование C99 6.9.2 Определения внешних объектов, которые гласят:

До C90 реализации сильно варьировались в отношении вперед ссылки на идентификаторы с внутренней связью (см. п. 6.2.2). C89 комитет изобрел концепцию пробного определения для обработки этого ситуация. Предварительное определение - это объявление, которое может или не может действовать как определение: если фактическое определение будет найдено позже в перевод, то предварительное определение просто действует как декларация. Если нет, то предварительное определение действует как фактическое определение. Для согласованности применяются те же правила для идентификаторы с внешней связью, хотя они не являются строго необходимо.

и раздел 6.2.2 из объяснения C99 гласит:

Модель определения, используемая для объектов с внешней связью, была основная проблема стандартизации C89. Основная проблема заключалась в том, чтобы решить какие объявления объекта определяют хранилище для объекта и которые просто ссылаются на существующий объект. Связанная с этим проблема разрешено ли множественное определение хранилища, или только одно из них приемлемо. Пред-C89-реализация демонстрирует не менее четырех различных модели, перечисленные здесь в порядке возрастания ограничений:

Ответ 2

Вот пример случая, когда он полезен:

void (*a)();

void bar();
void foo()
{
    a = bar;
}

static void (*a)() = foo;

/* ... code that uses a ... */

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