C 读取未初始化的值是否始终是未定义的行为?还是有例外?
读取值时,(UB)的一个明显示例是: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,或者是否存在例外情况?使用未初始化
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对齐
运算符、一元&
运算符、++
运算符、
--
运算符,或
运算符的左操作数或
赋值运算符,没有数组类型的左值
转换为存储在指定对象中的值
(不再是左值);这就是所谓的左值
转变如果左值具有限定类型,则该值具有
左值类型的不合格版本;另外,,
如果左值具有原子类型,则该值具有非原子版本
左值的类型;否则,该值具有
左值的类型。如果左值的类型不完整,并且
没有数组类型,行为未定义如果左值
指定自动存储持续时间的对象,该对象可以
已使用寄存器
存储类声明(从未使用过
地址),并且该对象未初始化(未声明)
使用初始值设定项,且未对其进行赋值
在使用前执行),行为未定义。