Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.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 为什么printf()在应该为0时提供随机输出?_C_Gcc_Printf_C99 - Fatal编程技术网

C 为什么printf()在应该为0时提供随机输出?

C 为什么printf()在应该为0时提供随机输出?,c,gcc,printf,c99,C,Gcc,Printf,C99,因此,printf是一个函数,如果成功,它将返回写入的字符数;如果发生错误,它将返回负值。看看这个示例,预期的输出为零 现在,当我添加更多这些%d时: 输出更改为: 0 134513819-1216430092 134513808 我不知道随机垃圾值是怎么回事?输出中也有一个负值,负值证明错误是正确的,所以有人能准确地指出错误是什么吗? 请简明扼要。谢谢。因为%d表示需要一个整数。你没有通过任何考试,所以你的行为没有定义 请注意,g++4.8.2给出了一个有用的警告: 警告:格式“%d”需要匹配

因此,printf是一个函数,如果成功,它将返回写入的字符数;如果发生错误,它将返回负值。看看这个示例,预期的输出为零

现在,当我添加更多这些%d时: 输出更改为: 0 134513819-1216430092 134513808

我不知道随机垃圾值是怎么回事?输出中也有一个负值,负值证明错误是正确的,所以有人能准确地指出错误是什么吗? 请简明扼要。谢谢。

因为%d表示需要一个整数。你没有通过任何考试,所以你的行为没有定义

请注意,g++4.8.2给出了一个有用的警告:

警告:格式“%d”需要匹配的“int”参数[-Wformat=]

与clang++3.4类似:

警告:转换“%”多于数据参数[-Wformat]


您错误地指定了要打印的格式字符串。这是,您不应该对结果有任何期望。通过指定%d,您告诉printf需要一个尚未提供的int参数

如果我们看C99标准草案第7.19.6.1节,fprintf函数也涵盖了与格式说明符有关的pritnf,它说:

[…]如果格式的参数不足,则行为未定义。[…]


问题在于你如何提出问题;您假定它应该是0。事实上,这是未定义的行为,printf将替换堆栈中发生的任何%d。

预期的输出为零

当程序调用未定义的行为时,您不应该期望任何结果

C99,7.19.6.1p2[…]如果格式的参数不足,则行为为 未定义。[…]

您的代码调用未定义的行为。任何事情都有可能发生

C11标准在第7.21.6节格式化输入/输出功能中规定:

如果任何参数不是相应转换规范的正确类型,则行为未定义


您没有为相应的%d说明符传递任何参数

目前有两个问题:第一个问题是为什么编译器没有发出一个关于printf错误调用的错误,第二个问题是为什么会得到垃圾输出。我一次只回答一个问题

printf是一个复杂的函数。虽然大多数函数都有恒定数量的参数传递给它们,但printf是不同的。 例如,如果我们采用这个简单函数:

int max(int a, int b) {
  if (a > b) return a;
  else return b;
}
您可以看到,此函数始终接收2个参数。这也是编译器知道的,并在编译代码时强制执行。这就是为什么像max4这样的调用不起作用。编译器将看到我们传递的是max 1参数而不是2参数,它将发出一个错误

printf是一个接受可变数量参数的函数,该数量由格式字符串中以%开头的格式说明符数量决定。这意味着编译器在编译时无法知道传递给printf的参数数量是否足够或太多

垃圾打印的原因是函数如何读取其输入参数。函数的所有输入参数都位于堆栈上。在调用函数之前,这些函数被推送到堆栈中,之后由函数寻址。在本例中,由于%d,printf希望在格式字符串之外有一个额外的参数,因此它在第二个参数所在的地址中查找。唉,这个参数没有被传递,所以它实际上会查看堆栈中可能包含任何其他内容的位置:返回地址、帧指针、封闭范围的局部变量或其他


您可以阅读有关函数调用如何工作的更多信息。

您从未实际检查printf的返回值。printf的返回值与它应该写入stdout的内容之间存在巨大差异。两件完全不同的事情。@remyabel:这不是问题所在。@remyabel:没有人会这样做,我想不出任何实现在这里会起到什么作用。大多数现代编译器都会对此代码发出警告。我不希望printf在这里返回错误结果。并不是说它不能,只是没有现有的实现。@DietrichEpp同意,未定义的行为就是未定义的行为。好吧,我明白了,但为什么我们一开始就得到零?我的意思是如果它是一个未定义的行为,那么第一个也应该是一些随机值。未定义的意思是行为没有定义。任何事情都有可能发生。但是为什么我们第一次得到零分呢?@syedamedul:未定义的行为意味着任何事情都可能发生。打印零是发生任何事情的一个例子。问为什么是毫无意义的。正如我已经说过的,在UB的情况下,任何事情都可能发生。无法保证第一位的值始终为0。结果可能是
不同的编译器,甚至在同一个编译器的不同版本上有所不同。这意味着编译器在编译时无法知道传递给printf的参数数量是否足够,这是错误的。当格式字符串是字符串文字时,如OP示例中所示,是什么阻止编译器知道尾随参数的数量不正确?当格式字符串是文字时,是一种特殊情况,编译器知道这一点。然而,在一般情况下,它不能知道。
printf("%d");
int max(int a, int b) {
  if (a > b) return a;
  else return b;
}