Можем ли мы объявить объект структуры в области файла перед определением структуры?

#c

#c

Вопрос:

В соответствии с приведенным ниже кодом и ответом на него:

Вопрос: Какое из следующих объявлений структуры выдаст ошибку?

  1.  struct temp { char c; } s;
    int main(void) {}
      
  2.  struct temp { char c; };
    struct temp s;
    int main(void) {}
      
  3.  struct temp s; 
    struct temp { char c; };
    int main(void) {}
      
  4. Ничего из вышеперечисленного.

Ответ: 4

Это правильно? Можем ли мы сначала объявить объект структуры и только потом определение структуры?

Комментарии:

1. Все показанные функции являются нестандартными для всего текущего тысячелетия. Все структуры искажены. Ни один код не должен компилироваться.

2. Предполагается, что вы не сможете скомпилировать пустое тело структуры. В (c) нет типа struct temp , s который номинально определен, поэтому переменная не должна быть определяемой. Где-то может быть карта, освобождающая от тюрьмы; У меня нет компилятора C на моем iPhone.

3. @JonathanLeffler Вопрос касается порядка объявлений, элементы структуры не имеют значения. Я добавил int main и элемент структуры, и он по-прежнему компилируется без предупреждений. Я также добавил тело main , которое обращается к элементу структуры, никаких жалоб. Я так же удивлен, как и OP.

4. Я сплю. Теперь мой робот отвечает. Если утром все еще будут разногласия, я посмотрю. Если вам когда-нибудь нужны были доказательства того, почему вопросы с несколькими вариантами ответов отвратительны, это иллюстрирует суть. Вы не можете представить рассуждения на экзамене.

5. @jonathan: Пустые структуры являются расширением GCC для C.

Ответ №1:

Да, C иногда бывает странным. Поскольку эта переменная находится в области видимости файла и не имеет инициализатора или спецификатора класса хранения, она представляет собой предварительное определение. Стандарт C определяет его следующим образом:

6.9.2 Определения внешних объектов

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

Я подчеркнул соответствующую часть. Поскольку в вашей переменной нет инициализатора, это как если бы вы записали его в самом конце файла и инициализировали нулем. Физический макет файла не имеет значения, потому что логически определение типа структуры доступно в конце файла.

Итак, ответ действительно (4). Я бы не стал писать подобный код в реальной жизни, однако это ужасно сбивает с толку в экосистеме C, где почти все должно быть предварительно объявлено для использования.