Прыжки через переменную инициализации плохо сформированы или это вызывает неопределенное поведение?

17

Рассмотрим этот код:

void foo()
{
    goto bar;
    int x = 0;
    bar: ;
}

GCC и Clang отклоняют это , потому что переход к bar:обходу инициализации переменной. MSVC вообще не жалуется (кроме случаев, xкогда bar:вызывает предупреждение).

Мы можем сделать аналогичную вещь с switch:

void foo()
{
    switch (0)
    {
        int x = 0;
        case 0: ;
    }
}

Теперь все три компилятора выдают ошибки .

Эти фрагменты плохо сформированы? Или они вызывают UB?

Раньше я думал, что оба были плохо сформированы, но я не могу найти соответствующие части стандарта. [stmt.goto] ничего не говорит об этом, как и [stmt.select] .

HolyBlackCat
источник
1
Вопрос будет более тривиальным, если вы используете xпосле прыжка.
Jarod42
1
не стандарт, но здесь можно найти некоторую информацию об этом: en.cppreference.com/w/cpp/language/goto, в частности: «Если передача контроля входит в область действия любых автоматических переменных (например, путем перехода вперед через объявление заявление), программа плохо сформирована (не может быть скомпилирована), если только ... "
idclev 463035818
Добавьте /permissive-флаг в MSVC, и он также будет жаловаться. Однако я не знаю, является ли поведение MSVC без этого флага четко определенным (я бы предположил, иначе, почему они это допустили?).
грецкий орех
@walnut «в противном случае, почему они это допустят?» Возможно, для обратной совместимости, или потому что они не слишком заботятся о стандарте. Все основные компиляторы не соответствуют стандарту при настройках по умолчанию.
HolyBlackCat
stackoverflow.com/a/7334968/4386278
Астероиды с крыльями

Ответы:

20

Он плохо сформирован, когда инициализация не пустая.

[Stmt.dcl]

3 Можно передавать в блок, но не так, чтобы обойти объявления с инициализацией (в том числе в условиях и инструкциях init). Программа, которая переходит от точки, где переменная с автоматическим сроком хранения не находится в области видимости, к точке, где она находится в области видимости, плохо сформирована, если переменная не имеет бессодержательной инициализации ([basic.life]). В таком случае переменные с незаполненной инициализацией строятся в порядке их объявления.

Инициализатор делает инициализацию незаполненной. В отличие от этого

void foo()
{
    goto bar;
    int x; // no initializer
    bar: ;
}

будет хорошо сформирован. Хотя обычные предостережения об использовании xс неопределенным значением будут применяться.

Рассказчик - Unslander Monica
источник
разве объявления переменных не должны быть первым делом в области видимости?
Cruncher
4
@ Cruncher - C89 требовал этого. C ++ никогда не делал, как и современный C.
StoryTeller - Unslander Моника
3

Из заявления goto :

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

  1. скалярные типы, объявленные без инициализаторов
  2. типы классов с тривиальными конструкторами по умолчанию и тривиальными деструкторами, объявленными без инициализаторов
  3. cv-квалифицированные версии одного из вышеперечисленных
  4. массивы одного из вышеперечисленных
Искатель правды
источник