почему эта программа отлично компилируется в C11, но не в C99?

Рассмотрим следующую программу: (см. живую демонстрацию здесь).

#include <stdio.h>
struct Test
{
    int a;
};
typedef struct Test t;
typedef struct Test t;
int main()
{
    t T={9};
    printf("%d",T.a);
}

Программа отлично компилируется в компиляторе C11, но не компилируется в компиляторе C99. Почему? Какова причина? Мой компилятор gcc 4.8.1 выдает следующие предупреждения:

[Warning] redefinition of typedef 't' [-Wpedantic]
[Note] previous declaration of 't' was here

person Destructor    schedule 21.10.2015    source источник
comment
Компилятор дает вам подсказку или просто отказывается компилировать это без каких-либо сообщений об ошибках?   -  person juanchopanza    schedule 21.10.2015
comment
@PravasiMeet Нет, потому что сегодня у меня не осталось голосов, но, вероятно, потому, что вашему вопросу не хватает тщательности, а ошибки, которые вы получаете, отсутствуют.   -  person magisch    schedule 21.10.2015
comment
@juanchopanza: по умолчанию GCC компилирует это как расширение компилятора, но если я использую параметр -pedantic-errors, компиляция завершается ошибкой? Компилятор выдает предупреждения.   -  person Destructor    schedule 21.10.2015
comment
Интересный. И вы хотите сохранить эти предупреждения/ошибки в секрете? Или вы можете поделиться ими с нами?   -  person juanchopanza    schedule 21.10.2015
comment
@PravasiВстретьтесь с GCC, скомпилируйте с -std=c11 и -Wall, затем следуйте любым предупреждениям.   -  person RamblingMad    schedule 21.10.2015
comment
Выработайте привычку включать любые сообщения об ошибках/предупреждениях от компиляторов/компоновщиков.   -  person Martin James    schedule 21.10.2015
comment
@PravasiMeet, во всяком случае, жалобы на отрицательные голоса привлекут значительно больше внимания. И независимо от того, показывает ли ваш вопрос исследования и усилия, решать сообществу, а не вам.   -  person magisch    schedule 21.10.2015
comment
@tinky_winky: кто это сказал? Это совершенно точно определено.   -  person Destructor    schedule 21.10.2015
comment
@MartinJames ТАК работает не так. Вы минусуете, чтобы поощрить правки. Если проблемы с публикацией устранены, понижение больше не блокируется и может быть удалено.   -  person Lundin    schedule 21.10.2015
comment
В любом случае, как ботаник C, я думаю, что это был самый интересный вопрос сегодня, +1.   -  person Lundin    schedule 21.10.2015
comment
Нашел дубликат, когда искал обоснование.   -  person Lundin    schedule 21.10.2015


Ответы (1)


Это было (очевидно) изменено в C11. C99§6.7/3:

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

C11§6.7/3:

Если идентификатор не имеет связи, должно быть не более одного объявления идентификатора (в описателе или спецификаторе типа) с той же областью действия и в одном и том же пространстве имен, за исключением того, что:

имя typedef может быть переопределено для обозначения того же типа, что и сейчас, при условии, что этот тип не является изменяемым типом;

- теги могут быть повторно объявлены, как указано в 6.7.2.3.

Хотя я не могу найти документ с обоснованием для C11, я предполагаю, что причина этого изменения заключается в том, чтобы разрешить несколько struct typedef, возможно, по нескольким заголовкам. Поскольку повторное объявление тегов struct/union/enum уже разрешено, а typedefing structs является довольно распространенной идиомой.

Изменить

@Lundin нашел обоснование для этого: это для улучшения совместимости с С++:

C++ позволяет переопределению typedef с тем же именем, что и у предыдущего typedef, появляться в той же области, если оно называет тот же тип. Некоторые компиляторы C допускают аналогичное переопределение typedef в качестве расширения, хотя C99 этого не позволяет. Добавление мягкого переопределения typedef в C1x повысит согласованность с C++, стандартизирует некоторые существующие практики и безопасно устранит ограничение, которое бесполезно и иногда доставляет неудобства пользователям.

person Kninnug    schedule 21.10.2015
comment
Насколько это странно? Я верю вам и проголосовал, но мне просто интересно, почему они это сделали? - person Martin James; 21.10.2015
comment
@MartinJames, мне тоже это показалось странным. Мое предположение состояло бы в том, чтобы разрешить несколько typedef одного и того же в нескольких заголовках, как это могут быть теги. Тем более, что typedef struct { ... } type; комбо так популярны. - person Kninnug; 21.10.2015
comment
У меня есть некоторые смутные воспоминания о том, что С++ допускает несколько определений типов, так что это может быть попыткой согласовать C с C++? Что касается обоснования этого в C++, я понятия не имею. - person Lundin; 21.10.2015
comment
@Lundin разве С++ не автоматически typedef structs использует свой тег (struct foo { ... }; -> typedef struct foo { ... } foo;)? Они могли бы позволить ему разместить избыточные typedef, поступающие из C. Таким образом, гармонизация прошла полный круг :). - person Kninnug; 21.10.2015
comment
@Kninnug Ответ на дубликат, который я связал, кажется, предполагает, что это действительно было для гармонизации C ++. Это единственное объяснение, которое я могу найти. - person Lundin; 21.10.2015
comment
Нашел обоснование. - person Lundin; 21.10.2015
comment
@Lundin хорошо. Отредактировал мой ответ, для чего он все еще стоит... - person Kninnug; 21.10.2015