Чи перехід через ініціалізацію змінної неправильно сформований чи це викликає не визначену поведінку?


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] .


1
Випуск був би більш тривіальним, якщо ви використовуєте xпісля стрибка.
Jarod42

1
не стандартний, але тут можна знайти деяку інформацію про нього: en.cppreference.com/w/cpp/language/goto, зокрема: "Якщо передача управління потрапляє в область будь-яких автоматичних змінних (наприклад, перескакуючи вперед через декларацію заява), програма неправильно сформована (неможливо скомпілювати), якщо тільки ... "
idclev 463035818

Додайте /permissive-прапор до MSVC, і він також скаржиться. Я не знаю, хоча чітко визначена поведінка MSVC без цього прапора (я б припустив, інакше навіщо вони це дозволять?).
волоський горіх

@walnut "інакше чому б вони це дозволили" Можливо, для зворотної сумісності або тому, що вони не надто піклуються про стандарт. Усі основні компілятори не відповідають стандарту за замовчуванням.
HolyBlackCat

Відповіді:


20

Це неправильно формується, коли ініціалізація не є вакуумною.

[stmt.dcl]

3 Можна перенести в блок, але не таким чином, щоб обходити декларації з ініціалізацією (у тому числі в умовах та init-операторах). Програма, яка стрибає з точки, коли змінна з автоматичною тривалістю зберігання не перебуває в області, до точки, де вона знаходиться в області дії, неправильно формується, якщо змінна не має вакуумної ініціалізації ([basic.life]). У такому випадку змінні з вакуумною ініціалізацією будуються в порядку їх оголошення.

Ініціалізатор робить ініціалізацію не вакуумною. На противагу цьому

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

була б добре сформована. Хоча застосовуються звичайні застереження щодо використання xз невизначеним значенням.


чи не все-таки декларування змінних має бути першим ділом в області застосування?
Cruncher

4
@Cruncher - C89 цього вимагав. C ++ ніколи не робив, а також сучасний C вже не працює.
StoryTeller - Невідповідна Моніка

3

З goto заяви :

Якщо передача управління потрапляє в область будь-яких автоматичних змінних (наприклад, перестрибуючи вперед через заяву декларації), програма неправильно формується (неможливо скомпілювати), якщо тільки всі змінні, область яких введено, мають

  1. скалярні типи, оголошені без ініціалізаторів
  2. типи класів із тривіальними конструкторами за замовчуванням та тривіальними деструкторами, оголошеними без ініціалізаторів
  3. версії одного з вищезазначених, кваліфіковані cv
  4. масиви одного з перерахованих вище
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.