对未初始化变量的任何保证?

有许多声称使用未初始化的变量会调用未定义的行为(UB) 。
仔细阅读文档,我无法validation该声明,所以我想要一个令人信服的论点,为C和C ++澄清这一点。
我期望两者都有相同的语义,但我准备对微妙或不那么微妙的差异感到惊讶。

使用未初始化变量开始的一些示例。 请根据需要添加其他人,以解释他们未涵盖的任何角落案例。

void test1() { int x; printf("%d", x); } void test2() { int x; for(int i = 0; i < CHAR_BIT * sizeof x) x = x << 1; printf("%d", x); } void test3() { unsigned x; printf("%u", x); /* was format "%d" */ } void test4() { unsigned x; for(int i = 0; i < CHAR_BIT * sizeof x) x = x << 1; printf("%u", x); /* was format "%d" */ } 

在C中,所有这些都是未定义的行为,但出于一个可能不会直接考虑的原因。 访问具有不确定值的对象具有未定义的行为,如果它是“无记忆”的,即6.3.2.1 p2

如果左值指定了一个自动存储持续时间的对象,该对象可以使用寄存器存储类声明(从未使用其地址),并且该对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行任何赋值) ),行为未定义。

否则,如果采取了地址,那么在这种情况下对具体不确定性的解释并不是一致的。 有些人一旦首次阅读就会期望这样的价值得到修复,有些人会说每次访问时可能会有不同的“woobly”(左右)值。

总之,不要这样做。 (但你可能已经知道了。)

(而不是使用“%d”来解决unsigned的错误。)

C

C11 6.7.9 / 10

如果未显式初始化具有自动存储持续时间的对象,则其值不确定。

不确定值的处理方式如下:

C11 6.2.6.1/5

某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示,并且由不具有字符类型的左值表达式读取,则行为是未定义的。 如果这样的表示是由副作用产生的,该副作用通过不具有字符类型的左值表达式修改对象的全部或任何部分,则行为是未定义的50)。 这种表示称为陷阱表示。

对上述规范性文本有评论:

50)因此,可以将自动变量初始化为陷阱表示而不会导致未定义的行为, 但是在其中存储适当的值之前,不能使用该变量的值。

(强调我的)

此外,左移一个包含不确定值的signed int变量也可能导致未定义的行为,以防它被解释为否定行为:

C11 6.5.7 / 4

E1 << E2的结果是E1左移E2位位置; 腾出的位用零填充。 如果E1具有无符号类型,则结果的值为E1×2E2,模数比结果类型中可表示的最大值减1。 如果E1具有有符号类型和非负值,并且在结果类型中可以表示E1×2E2,那么这就是结果值; 否则,行为未定义。

所有四种情况都会在C中调用未定义的行为 ,因为未初始化的自动变量从不采用其地址。 看到不同的答案。

顺便说一下, sizeof(x) 定义的,因为表达式实际上没有被评估:它是一个衰减到类型的编译时评估。

在最新的C ++ 1y草案( N3936 )中,这显然是未定义的行为,因为关于不确定值和未定义行为的语言已经澄清 ,现在在第8.5节中说明:

[…]如果评估产生不确定值,则行为不明确,但以下情况除外;

并继续列出一些无符号窄字符类型的exception。

以前在C ++中,我们不得不依赖于未指定的左值到右值的转换来certificate未定义的行为,这在一般情况下是有问题的。 在这种情况下,我们确实有一个lalue-to-rvalue转换。 如果我们看一下5.2.2函数调用段落7强调我的 ):

当给定参数没有参数时,参数的传递方式使得接收函数可以通过调用va_arg(18.10)来获取参数的值。 […] 对参数表达式执行 左值到右值(4.1) ,数组到指针(4.2)和函数到指针(4.3) 标准转换

关于C,所有示例的行为可能是未定义的:

章和节

3.19.2
1 不确定的价值
要么是未指定的值,要么是陷阱表示

6.2.6类型的表示
6.2.6.1总则

5某些对象表示不需要表示对象类型的值。 如果对象的存储值具有这样的表示,并且由不具有字符类型的左值表达式读取,则行为未定义。 如果这样的表示是由副作用产生的,该副作用通过不具有字符类型的左值表达式来修改对象的全部或任何部分,则该行为是未定义的。 50)这种表示称为陷阱表示。

50)因此,可以将自动变量初始化为陷阱表示而不会导致未定义的行为,但是在其中存储适当的值之前,不能使用该变量的值。

在所有四种情况下, x都有自动存储持续时间,并且没有明确初始化,这意味着它的值是不确定的; 如果此不确定值是陷阱表示,则行为未定义。

编辑

删除了对附录J的引用,因为它是非规范性的。