【发布时间】:2009-10-07 10:05:53
【问题描述】:
当我尝试在一个简单的 c 文件中运行编译并执行此语句时:
main(){ printf("%d");}
在 HP 上给我 64,在 AIX 上给我 804359524。
谁能告诉我这是什么行为。
【问题讨论】:
当我尝试在一个简单的 c 文件中运行编译并执行此语句时:
main(){ printf("%d");}
在 HP 上给我 64,在 AIX 上给我 804359524。
谁能告诉我这是什么行为。
【问题讨论】:
我假设你的意思是:
int main()
{
printf("%d");
}
在这种情况下,printf() 正在从堆栈中读取一个 int(按照格式说明符 %d 的指示)。由于您没有指定一个,它只是读取堆栈上的任何内容并使用它。因此,您看到的伪随机输出。
请尝试:
int main()
{
printf("%d", 10101);
}
HTH
【讨论】:
这是经典的undefined behavior。编译器不会检查您是否提供了足够的参数来匹配您的格式化字符串。有编译器可以做到这一点 (gcc is one),但你的没有。
printf() 中的代码将愉快地遍历其给定的格式化字符串,当它到达 "%d" 时,它将读取一个 int 大小的参数(通常:从堆栈中),不知道那里没有任何论据可供阅读。
堆栈上的任何值都会被打印出来。
【讨论】:
如果您指定足够高的警告级别,某些编译器(如 gcc)会捕获这种常见的问题。像这样(编译你的代码,带有 -Wall - 所有警告):
gcc -c -g -Wall -MMD -MP -MF build/Debug/Cygwin-Windows/newmain.o.d -o build/Debug/Cygwin-Windows/newmain.o newmain.c
newmain.c: In function `main':
newmain.c:16: warning: too few arguments for format
这是始终以高警告级别编译并认真对待警告消息的大约 998 个充分理由之一。
【讨论】:
代码暴露了未定义的行为。在其他系统上,它可能会打印“堆栈溢出”,(说真的!)。 %d 告诉 CRT 库您将提供一个整数,但您没有。
【讨论】:
我的猜测是你编译
main(){ printf("%d");}
这将从当前堆栈中选择一个随机值。试试这个:
main() {
printf("%d", 0);
printf("%d");
}
现在,第二个printf() 将始终打印0,因为它与第一个调用获得相同的堆栈。
[编辑] 这不适用于带有 GCC 4.1.2 的 x86 Linux。这是生成的汇编代码(使用gcc -S -o t.s t.c):
movl $0, %esi
movl $.LC0, %edi
movl $0, %eax
call printf
movl $.LC0, %edi
movl $0, %eax
call printf
如您所见,第二个参数没有被压入堆栈,而是通过%esi(这是一个寄存器)传递。同一个寄存器可能在printf() 中被修改,这就是它失去价值的原因。该死的优化;)
【讨论】: