Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 读取未初始化的值是否始终是未定义的行为?还是有例外?_C - Fatal编程技术网

C 读取未初始化的值是否始终是未定义的行为?还是有例外?

C 读取未初始化的值是否始终是未定义的行为?还是有例外?,c,C,读取值时,(UB)的一个明显示例是: int a; printf("%d\n", a); 下面的例子怎么样 int i = i; // `i` is not initialized when we are reading it by assigning it to itself. int x; x = x; // Is this the same as above? int y; int z = y; 上述三个示例是否都是UB,或者是否存在例外情况?使用未初始化

读取值时,(UB)的一个明显示例是:

int a;
printf("%d\n", a);
下面的例子怎么样

int i = i;     // `i` is not initialized when we are reading it by assigning it to itself.
int x; x = x;  // Is this the same as above?
int y; int z = y;

上述三个示例是否都是UB,或者是否存在例外情况?

使用未初始化的自动存储持续时间对象调用UB


未初始化的静态存储持续时间对象的使用定义为初始化为0

int a;

int foo(void)
{
    static int b;
    int c;
    
    int d = d;           //UB
    static int e = e;    //OK

    printf("%d\n", a);   //OK
    printf("%d\n", b);   //OK
    printf("%d\n", c);   //UB

}

使用未初始化的自动存储持续时间对象调用UB


未初始化的静态存储持续时间对象的使用定义为初始化为0

int a;

int foo(void)
{
    static int b;
    int c;
    
    int d = d;           //UB
    static int e = e;    //OK

    printf("%d\n", a);   //OK
    printf("%d\n", b);   //OK
    printf("%d\n", c);   //UB

}

三行中的每一行都会触发。解释这一点的关键部分是第6.3.2.1p2节关于转换:

除非它是
sizeof
运算符的操作数,否则
\u对齐
运算符、一元
&
运算符、
++
运算符、
--
运算符,或
运算符的左操作数或 赋值运算符,没有数组类型的左值 转换为存储在指定对象中的值 (不再是左值);这就是所谓的左值 转变如果左值具有限定类型,则该值具有 左值类型的不合格版本;另外,, 如果左值具有原子类型,则该值具有非原子版本 左值的类型;否则,该值具有 左值的类型。如果左值的类型不完整,并且 没有数组类型,行为未定义如果左值 指定自动存储持续时间的对象,该对象可以 已使用
寄存器
存储类声明(从未使用过 地址),并且该对象未初始化(未声明) 使用初始值设定项,且未对其进行赋值 使用前执行),行为未定义。

在这三种情况中,未初始化的变量都用作赋值或初始化的右侧(在这方面相当于赋值),并进行左值到右值的转换。粗体部分适用于此处,因为相关对象尚未初始化

这也适用于
int i=i大小写,因为右侧的左值尚未初始化

在一个相关问题中有一个争论,即
inti=i
是UB,因为
i
的生存期尚未开始。然而,情况并非如此。根据第6.2.4节p5和p6:

5如果对象的标识符声明时没有链接且没有存储类说明符
static
,则该对象将自动 存储持续时间,以及一些复合文字。结果 试图通过自动存储间接访问对象 对象所在线程以外的线程的持续时间 定义了相关的实现

6对于没有可变长度数组类型的对象,其生存期从进入块开始 它与之关联,直到该块的执行以任何方式结束 方式。(输入封闭块或调用函数 暂停但不结束当前块的执行。)如果 递归地输入块,创建对象的新实例 每次都创建。对象的初始值为 不确定的如果为 对象,则每次声明或复合 在执行块时达到文本;否则 每次到达声明时,该值都变得不确定

因此在这种情况下,
i
的生存期在遇到声明之前开始。所以
inti=i仍然是未定义的行为,但不是因为这个原因

然而,6.3.2.1p2的粗体部分确实为未初始化变量的使用打开了大门,而该变量不是未定义的行为,也就是说,如果该变量的地址已被获取。例如:

int a;
printf("%p\n", (void *)&a);
printf("%d\n", a);
在这种情况下,如果:

  • 实现没有给定类型的陷阱表示,或
  • a
    选择的值恰好不是陷阱表示

在这种情况下,
a
的值是未指定的。特别是,本例中的and(MSVC)就是这种情况,因为这些实现没有整数类型的陷阱表示。

三行触发器中的每一行。解释这一点的关键部分是第6.3.2.1p2节关于转换:

除非它是
sizeof
运算符的操作数,否则
\u对齐
运算符、一元
&
运算符、
++
运算符、
--
运算符,或
运算符的左操作数或 赋值运算符,没有数组类型的左值 转换为存储在指定对象中的值 (不再是左值);这就是所谓的左值 转变如果左值具有限定类型,则该值具有 左值类型的不合格版本;另外,, 如果左值具有原子类型,则该值具有非原子版本 左值的类型;否则,该值具有 左值的类型。如果左值的类型不完整,并且 没有数组类型,行为未定义如果左值 指定自动存储持续时间的对象,该对象可以 已使用
寄存器
存储类声明(从未使用过 地址),并且该对象未初始化(未声明) 使用初始值设定项,且未对其进行赋值 在使用前执行),行为未定义。