我从printf()
电话中取出年龄变量,看看会发生什么。然后我用make编译它。它似乎只会抛出更多%转换的警告,而不是数据参数和未使用的年龄变量,但没有编译错误。然后我运行可执行文件,它确实运行。只有每次运行它时,它都会返回不同的随机整数。我想知道导致这种行为的原因是什么?
#include <stdio.h>
int main(int argc, char *arg[]) {
int age = 10;
int height = 72;
printf("I'm %d years old\n");
printf("I'm %d inches tall\n", height);
return 0;
}
答案 0 :(得分:4)
根据printf()
规范,如果所需格式说明符的参数数量不足,则会调用undefined behavior。
所以,你的代码
printf("I'm %d years old\n");
缺少%d
的必需参数,调用UB并且不保证产生任何有效结果。
交叉引用,C11
标准,章节§7.21.6.1
[..]如果格式的参数不足,则行为是 未定义。 [..]
答案 1 :(得分:1)
根据C标准(7.21.6.1 fprintf函数 - 同样适用于printf)
- ... 如果格式的参数不足,则行为未定义。如果参数格式耗尽 剩下的,多余的参数被评估(一如既往),但是 否则被忽略。
醇>
答案 2 :(得分:1)
使用cdecl的printf,它使用堆栈参数。如果你暗示你正在使用一个参数的函数,它将被拉出运行时堆栈,如果你没有把你的数字放在那里,那么这个地方可能包含一些垃圾数据。因此,将要打印的参数是一些任意数据。
答案 3 :(得分:0)
除了我所知道的一个例外,C标准对任何可能有用的实施中的任何动作都没有要求。不难想象一个C编译器传递一个像printf
这样的可变参数函数,表明它已经传递了什么参数,也不难让一个实现者认为让编译器触发陷阱是有用的。当相应的参数是某种其他类型或根本不存在时,代码会尝试检索某种类型的可变参数。因为在这种情况下使编译器陷阱可能是有用的,并且因为这样的陷阱的行为将超出标准的管辖范围,所以当可变函数试图接收参数时,标准不对可能发生或可能不发生的内容施加任何要求。没有传递给它。
在实践中,大多数编译器只是具有描述非可变参数的位置与后续可变参数的位置之间的关系的约定,而不是让可变函数知道它们收到了多少个参数。生成的代码将不知道函数是否已经接收到例如类型为int
的两个参数,但它会知道每个这样的参数(如果它存在)将存储在某个位置。在这样的编译器上,使用多余的格式说明符通常会导致生成的代码查看存在其他参数的位置。在许多情况下,这个位置将被用于其他目的,然后被放弃,并且可能为此目的保存那里存储的最后一个值,但通常没有理由对被遗弃的内存的内容有任何特别的期望。