如果a未初始化,是^ a还是aa未定义的行为?

Dav*_*nan 74 c undefined-behavior

考虑这个程序:

#include <stdio.h>

int main(void)
{
    unsigned int a;
    printf("%u %u\n", a^a, a-a);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

是不确定的行为?

从表面上看,它a是一个未初始化的变量.所以这指向未定义的行为.但是a^a并且a-a等于0所有的价值a,至少我认为是这样的.有可能有某种方式来证明行为是明确定义的吗?

M.M*_*M.M 72

在C11中:

  • 如果a从未使用过地址,则根据6.3.2.1/2显式未定义(引用如下)
  • 它可以是陷阱表示(在访问时会导致UB).6.2.6.1/5:

某些对象表示不需要表示对象类型的值.

无符号整数可以具有陷阱表示(例如,如果它具有15个精度位和1个奇偶校验位,则访问a可能导致奇偶校验错误).

6.2.4/6表示初始值是不确定的,3.19.2中的定义是未指定的值或陷阱表示.

此外:正如Pascal Cuoq所指出的那样,在C11 6.3.2.1/2中:

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

这对于字符类型没有例外,因此该条款似乎取代了前面的讨论; x即使没有陷阱表示,访问也会立即未定义.此子句已添加到C11以支持实际上具有寄存器陷阱状态的Itanium CPU.


没有陷阱表示的系统:但是如果我们投入&x;使6.3.2.1/2的异议不再适用,并且我们在一个已知没有陷阱表示的系统上呢?然后该值是未指定的值.3.19.3 中未指定值的定义有点模糊,但DR 451澄清了这一点,其结论如下:

  • 在所述条件下的未初始化值似乎可以改变其值.
  • 对不确定值执行的任何操作都将具有不确定的值.
  • 当用于不确定的值时,库函数将显示未定义的行为.
  • 这些答案适用于没有陷阱表示的所有类型.

根据该决议,int a; &a; int b = a - a;结果b仍然具有不确定的价值.

请注意,如果不确定的值未传递给库函数,我们仍然处于未指定行为的范围(不是未定义的行为).结果可能很奇怪,例如if ( j != j ) foo();可以称之为foo,但是恶魔必须保持在鼻腔中.

  • @DavidHeffernan你**也可以**将对不确定数据的访问视为UB,因为即使没有陷阱值,你的编译器也可能.请参阅http://blog.frama-c.com/index.php?post/2013/03/13/indeterminate-undefined (14认同)

AnT*_*AnT 32

是的,这是未定义的行为.

首先,任何未初始化的变量都可以具有"破碎"(又称"陷阱")表示.即使单次尝试访问该表示也会触发未定义的行为.此外,即使是非陷阱类型(如unsigned char)的对象仍然可以获得特殊的平台相关状态(如NaT - Not-A-Thing - on Itanium),这些状态可能表现为其"不确定值".

其次,未初始化的变量不能保证具有稳定的值.对同一个未初始化变量的两次顺序访问可以读取完全不同的值,这就是为什么即使两个访问a - a都是"成功"(不是陷阱),仍然不能保证a - a将评估为零.

  • @Matt McNabb:DR#451在2013年10月和2014年4月的DR#260中基本上重申了相同的决定http://www.open-std.org/Jtc1/sc22/WG14/www/docs/dr_451.htm.DR#451的委员会响应明确指出"此观点重申了C99 DR260的立场" (4认同)
  • @Matt McNabb:嗯,这可能是一个通过不同语言规范解决的问题.但DR#260(http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm)的决议清楚地明确规定,具有不确定值的变量可以任意改变"他们自己". (2认同)