跳过变量初始化格式错误还是会导致不确定的行为?


17

考虑以下代码:

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

GCC和Clang 拒绝了它,因为跳转到bar:绕过了变量初始化。MSVC一点也不抱怨(使用x after 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 特别是:“如果控制权转移进入任何自动变量的范围(例如,通过跳过声明)语句),则程序的
格式

/permissive-标志添加到MSVC,它也会抱怨。我不知道没有该标志的MSVC的行为是否定义明确(我会这样假设,否则为什么他们会允许它?)。
胡桃

@walnut “否则他们为什么会允许它”可能是为了向后兼容,或者是因为他们不太在乎标准。在默认设置下,所有主要的编译器均不符合标准。
HolyBlackCat

Answers:


20

初始化为非空状态时,格式不正确。

[stmt.dcl]

3可以转移到一个块中,但是不能以一种绕过初始化声明的方式(包括条件和init语句中的声明)的方式进行转移。除非变量具有空虚的初始化([basic.life]),否则从具有自动存储持续时间的变量不在范围内的点跳转到其处于范围内的点的程序是错误的。在这种情况下,具有空虚初始化的变量按其声明顺序构造。

初始化程序使初始化成为非空的。相比之下,这

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

格式正确。尽管通常会使用x不确定的值进行警告。


变量声明不是一定要成为作用域中的第一件事吗?
Cruncher

4
@Cruncher-C89需要它。C ++从不这样做,现代C也不再。
StoryTeller-Unslander Monica

3

goto语句

如果控制权转移进入任何自动变量的范围(例如,通过跳过声明语句),则程序的格式不正确(无法编译),除非输入其范围的所有变量都具有

  1. 没有初始化程序声明的标量类型
  2. 具有琐碎的默认构造函数和琐碎的析构函数的类类型,而没有初始化程序的声明
  3. 以上其中一项的CV认证版本
  4. 以上之一的数组
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.