Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.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
未经验证的scanf调用是否会导致未定义的行为?_C_Undefined Behavior_C11 - Fatal编程技术网

未经验证的scanf调用是否会导致未定义的行为?

未经验证的scanf调用是否会导致未定义的行为?,c,undefined-behavior,c11,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 pri

以下代码段是否在发生错误时调用未定义的行为

#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;
}
在C90中,这是UB

对于C99和C11,从技术上讲,它不是,但输出是不确定的。甚至有可能,直接跟随的另一个
printf
将打印不同的值;未初始化的变量可能会在没有明确的程序操作的情况下发生变化。但是,请注意,未初始化的变量只有在其地址已被获取时才能被读取*)(这在这里的
scanf
调用中完成)。根据n1570 6.3.2.1 p2:

如果左值指定了一个具有自动存储持续时间的对象,该对象本可以使用
寄存器
存储类声明(从未获取其地址),并且该对象未初始化(未使用初始值设定项声明,并且在使用前未对其执行赋值),则该行为未定义

从理论上讲,这将允许

int n;
&n;
printf("%d\n", n);
但是编译器仍然可以基于第一次读取不会在第一次写入之前发生的假设对语句重新排序或分配寄存器,并忽略无副作用的
&n语句

出于任何实际目的,切勿读取未初始化的值。首先,你没有理由想这样做;第二,即使是一个未指定的值也允许进行超越性的优化:一些人认为“垃圾”值可以用来收集随机数的一些熵,这会导致加密软件中非常糟糕的错误,例如。对于偶数wierder示例,其中未初始化的值在与2相乘后为奇数,请参见例如(是的,不确定的时间2只是不确定,不是偶数,并且仅在其他方面不确定)

另见

*)C99中缺少引用的段落,但这应视为标准中的缺陷,而不是C11中的变更。C99在技术上定义了(对于没有陷阱表示的机器)读取任何未初始化的变量(尽管它们的值仍然是不确定的,并且看起来可能仍然是随机变化的,但它不是UB)


使用,这已得到纠正,但不是在C11之前。添加它是为了允许钛平台上的
NaT
(存在于寄存器中,但不存在于内存中的值),即使是没有陷阱表示的整数类型。我不知道上面代码中的
&n
是否对这样一个平台有任何影响(通过严格阅读C11,它应该,但我不会依赖它)。

绝对技术上正确的答案,但我应该指出,
gcc-std=c99
至少在某些版本中,优化了,就好像阅读不确定的内容是UB:No,根据DR 338的时间线,C11中的修订定义“本可以通过
寄存器
存储类声明”从未出现在C99的任何修订版本中。在TC3最终确定之前,DR 338于2007年3月9日提交,但委员会没有及时就TC3达成协议,变更出现在C11中。除非你有权访问官方的TC3,并且你坚持认为它包含了这个句子(我有草案N1256,我在其中的任何地方都找不到)。嗯。。因此,理想情况下,在
C90
中,应该编写极为防御性的代码。@MohitJain,我不确定。是否存在使用未初始化变量的实际用例?或者你说的是意外未初始化的变量?一些编译器可能会对此发出警告,例如,使用GCC对Wuninitialized进行初始化(您可能需要使用优化来启用必要的流分析)。然而,这并不可靠(并且提出了一个问题,至少在使用UB进行优化的情况下,它是否可靠)。@mafso:主要的使用情况是,当存在对象时,它主要出现在结构中,但也可能出现在复制到结构中的离散对象中(始终初始化)指示其他各种对象是否具有有意义的值。能够盲目复制“哪些对象具有有意义的值”标志以及所有可能具有或可能不具有有意义的值的对象,可能比尝试避免复制不具有有意义的值的对象要快。
int n;
&n;
printf("%d\n", n);