Moh*_*ain 3 c undefined-behavior c11
以下片段是否在发生错误时调用未定义的行为?
#include <stdio.h>
int main() {
int i; /* Indeterminate */
if (scanf("%d", &i) == 1) /* Initialize */
printf("%d\n", i); /* Success! Print read value */
else
printf("%d\n", i); /* Input failed! Is printing `i` UB or not? */
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果scanf失败怎么办,是否访问了未初始化的变量?
编辑
此外,如果我替换scanf("%d", &i)为my_initializer(&i):
int my_initializer(int *pi)
{
double room_temp_degc = get_room_temp_in_degc();
if(room_temp_degc < 12.0) {
// Cool
*pi = 42;
return 1;
} else {
return 0;
}
}
Run Code Online (Sandbox Code Playgroud)
在C90中,这是UB.
对于C99和C11,从技术上讲,它不是,但输出是不确定的.甚至可能,另一个printf直接跟随将打印不同的值; 如果没有程序的明确行动,未初始化的变量似乎会发生变化.但请注意,只有在取消地址时才能读取未初始化的变量*)(这在scanf调用中完成).从n1570 6.3.2.1 p2:
如果左值指定了一个自动存储持续时间的对象,该对象可以用
register存储类声明(从未使用过其地址),并且该对象未初始化(未使用初始化程序声明,并且在使用之前未对其进行任何分配) ,行为未定义.
理论上,这将允许类似的东西
int n;
&n;
printf("%d\n", n);
Run Code Online (Sandbox Code Playgroud)
但是编译器仍然可以根据在第一次写入之前没有发生第一次读取并忽略副作用自由&n;语句的假设来重新排序语句或分配寄存器.
出于任何实际目的,永远不要阅读未初始化的值.首先,没有理由你应该这样做; 第二,即使是未指定的值也允许进行优化:有些人认为"垃圾"值可用于收集随机数的一些熵,这会导致加密软件中出现非常糟糕的错误,例如参见Xi Wang的博客文章.对于一个更加简单的例子,在与2相乘后未初始化的值是奇数,请参见例如此博客(是的,不确定的时间2只是不确定的,不是偶数,只有其他方面是不确定的).
另见DR 260.
*) C99中缺少引用的段落,但这应被视为标准中的缺陷,而不是C11中的变更.C99使其在技术上定义(对于没有陷阱表示的机器)来读取任何未初始化的变量(尽管它们的值仍然是不确定的,并且可能仍然看起来随机变化,它不是UB).
使用DR 338,这已得到纠正,但不是在C11之前.它被添加到允许NaT在Titanium平台上存在(存在于寄存器中,但不存在于内存中的值),即使对于没有陷阱表示的整数类型也是如此.我不知道,如果&n上面的代码对这样的平台有任何影响(通过严格阅读C11,它应该,但我不会依赖它).
| 归档时间: |
|
| 查看次数: |
311 次 |
| 最近记录: |