Резюме
Потенциальное нарушение стандарта C связано с этим предложением в C 2018 6.8.5 3:
Часть объявления оператора for
должна декларировать толькоидентификаторы для объектов, имеющих класс хранения auto
или register
.
Поскольку struct { int i; float f; }
объявляет как тип, так и идентификатор, возникает вопрос о том, как интерпретировать 6.8.5 3. Похоже,для меня это:
- Вероятно, комитет намеревался запретить объявлять что-либо, кроме идентификаторов для
auto
или register
объектов. - Этот случай использования, когда тип случайно объявленвозможно, не рассматривался.
- Разрешение этого побочного заявления было бы безвредным и не слишком противоречащим намерению.
(Я хотел бы пригласить любого, кто более знаком с записями комитета C,довести до нашего сведения все, что имеет к этому отношение.)
(в этом ответе я даю ссылки на стандарт С 2018, но язык устарел и существует вus версии, возможно, с другой нумерацией пунктов или абзацев.)
Объявлены как тип, так и идентификатор
Объявление в следующем выражении for
объявляет оба идентификатора s
и безымянный тип:
for (struct { int i; float f; } s = { 0, 0 }; s.i < 25; ++s.i, s.f = s.i/10.f)
…
Мы знаем, что он объявляет тип, потому что C 2018 6.7.2.1 8 говорит:
Наличие списка struct-объявление-списка в структуре-or-union-спецификатор объявляет новый тип в единице перевода.
В соответствии с 6.7.2.1 1, struct { int i; float f; }
является спецификатором структуры или объединения, а внутри него int i; float f;
- список объявлений структуры.Итак, этот исходный код соответствует описанию 6.7.2.1 8, поэтому он объявляет тип.
Язык стандарта C неоднозначен
C 2018 6.8.5 3 говорит:
Часть объявления оператора for
должна объявлять идентификаторы только для объектов, имеющих класс хранения auto
или register
.
Что касается грамматики и использования английского языка,для этого предложения возможны несколько значений, включая:
- Единственное, что декларация должна объявить, - это идентификаторы для объектов, имеющих класс хранения
auto
или register
. - Единственные идентификаторыобъявление должно объявлять идентификаторы для объектов, имеющих класс хранения
auto
или register
. - Единственные идентификаторы для объектов, которые декларация должна объявить, являются идентификаторами для объектов, имеющих класс хранения
auto
или register
.
В первую очередь, проблема в том, что «только» не смежно с тем, что оно модифицирует.«Только» может быть изменение «идентификаторов» или «объектов» или «класса хранения». Можно предпочесть, чтобы модификатор модифицировал ближайшего к нему кандидата, но авторы предложений не всегда конструируют их таким образом.(Грамматически это может также изменить «наличие», таким образом квалифицируя объекты как имеющие только класс хранения auto
или register
и не имеющие ничего другого, например, не имеющие размера или других свойств. Мы легко исключаем это значение в семантическома не грамматические основания.)
Эти примеры иллюстрируют различия между значениями:
static int s // Prohibited by 1, 2, and 3.
extern int s(int) // Prohibited by 1 and 2, permitted by 3.
struct { int i; float f; } s // Prohibited by 1, permitted by 2 and 3.
int s // Permitted by 1, 2, and 3.
Эффекты могут осветить намерение
Не похоже, что есть причина для предпочтения какого-либоиз этих значений, основанных на трудностях реализации C. Чтобы увидеть это, учтите, что реализация C может легко переписать:
for (declaration; …; …) …
в эквивалентный код:
{ declaration; for (; …; …) … }
Таким образом, еслиРеализация C может поддерживать объявления и операторы for
в целом, она может поддерживать общие объявления в операторе for
без значительных дополнительных усилий.
Какова цель 6.8.5 3?
Декларация вfor
оператор обеспечивает удобство.Он обеспечивает хороший способ объявления некоторого итератора или другого объекта, используемого для управления циклом, при этом ограничивая область действия оператором for
(что является преимуществом для избежания ошибок).Он не предоставляет никаких новых функций.Учитывая это, я ожидаю, что 6.8.5 3 было написано с целью дать возможность декларации служить этой цели, не раскрывая ее для других целей.Было бы странным, хотя и не невозможным, использовать любое из первых двух приведенных выше примеров в выражении for
.
Если это так, я подозреваю, что поверхностное намерение комитета имело значение 1, но они это сделалине учитывать ситуацию, когда неназванный тип объявлен случайно.Когда мы размышляем над третьим примером, используя структуру, мы видим, что она необычна, но не слишком не соответствует общепринятому использованию выражения for
:
- Естественно, оно возникает какРешение проблемы, что только одна декларация может присутствовать в части объявления оператора
for
, но иногда полезно управлять циклом с несколькими объектами разных типов. - Это все еще объект савтоматическое создание хранилища, как предусмотрено для циклов
for
. - Технически объявленный тип не требуется вне цикла
for
.