未初始化的变量用作自己的初始化程序的行为是什么?

时间:2019-01-15 14:03:53

标签: c++ c initialization language-lawyer

我刚才注意到,可以使用c99c11c++11标准用clang / gcc / clang ++ / g ++编译以下代码。

int main(void) {
    int i = i;
}

即使使用-Wall -Wextra,也没有编译器报告警告。

通过将代码修改为int i = i + 1;并使用-Wall,他们可以报告:

why.c:2:13: warning: variable 'i' is uninitialized when used within its own initialization [-Wuninitialized]
    int i = i + 1;
        ~   ^
1 warning generated.

我的问题:

  • 为什么编译器甚至允许这样做?
  • C / C ++标准对此有何评论?具体来说,这是什么行为? UB还是取决于实施?

3 个答案:

答案 0 :(得分:10)

由于i在用于初始化自身时未初始化,因此当时具有不确定值。不确定值可以是未指定值陷阱表示

如果您的实现支持整数类型的填充位,而 if 所讨论的不确定值恰好是陷阱表示,则使用它会导致不确定的行为

如果您的实现没有具有整数填充,则该值只是未指定,并且没有没有未定义的行为。

编辑:

为进一步详细说明,如果i从未在某个时间获取其地址,则该行为仍然无法定义。 C11标准的6.3.2.1p2部分对此进行了详细说明:

  

如果左值指定自动存储的对象   寄存器存储可能已声明的持续时间   类(从未使用过其地址),并且该对象未初始化   (未使用初始化程序声明且未对其进行赋值   已经在使用前执行过),则行为未定义。

因此,如果您从不使用i的地址,那么您将有未定义的行为。否则,以上声明适用。

答案 1 :(得分:9)

这是警告,与标准无关。

通过“乐观”方法对警告进行启发。仅当编译器确定将要出问题时才发出警告。在这种情况下,您最好使用clanggcc的最新版本,如评论中所述(请参阅我的另一个相关问题:why am I not getting an "used uninitialized" warning from gcc in this trivial example?)。

无论如何,在第一种情况下:

int i = i;

什么也没做,因为已经有i==i。由于没有用,分配可能会被完全优化。对于不会将“自初始化”视为问题的编译器,您可以在没有警告的情况下执行此操作:

int i = i;
printf("%d\n",i);

这会触发警告,好吧:

int i;
printf("%d\n",i);

尽管如此,从现在开始i被视为已初始化

在第二种情况下:

int i = i + 1;

必须在未初始化的值和1之间进行计算。发生未定义的行为。

答案 2 :(得分:2)

我相信您可以在出现以下情况时得到警告

int i = i + 1; 

按预期,但是,即使出现以下情况,您仍希望显示警告:

int i = i;

也。

  

为什么编译器甚至允许这样做?

该语句没有天生的错误。请参阅相关讨论:

获得更多见识。

  

C / C ++标准对此有何看法?具体来说,这是什么行为? UB还是依赖于实现?

这是未定义的行为,因为类型int可以具有陷阱表示,并且您从未在讨论中使用过变量的地址。因此,从技术上讲,一旦尝试使用存储在变量i中的(不确定的)值,您将面临UB。

您应该打开编译器警告。在gcc中,