当我解决代码强制的编程问题时,我发现格式说明符“%I64d”在相同的格式字符串中多次使用时如下:
long long int a, b, c;
a = 1, b = 3, c = 5;
printf("%I64d %I64d %I64d\n", a, b, c);
输出
1 0 3
然而,当我分隔每个说明符时,例如:
long long int a, b, c;
a = 1, b = 3, c = 5;
printf("%I64d ", a);
printf("%I64d ", b);
printf("%I64d ", c);
puts("");
正如预期的那样输出:
1 3 5
这是一个ideone链接,可以看到上面的代码片段: http://ideone.com/f2udRB
请帮助我理解为什么会这样?如果这是未定义的行为,如何显示这样的输出?我怎样才能理解有时出现这种意外输出的原因?
答案 0 :(得分:11)
格式字符串%I64d
printf()
期望堆栈上有4个字节的数字,因为使用GNU printf I
表示"使用替代输出数字"并且64
表示"填充到64个字符"。剩下的d
代表一个带符号的32位整数。
但是您推送的是8字节数字,因为a, b, c
的类型为long long
。
数字低于2 ^ 32,因此在堆栈上看到(以4字节为单位)
1 0 3 0 5 0
printf仅解释前3个数字,其余数字将被丢弃。使用%lld
时,printf()
正确地将堆栈数据解释为8字节数字。
答案 1 :(得分:3)
请帮助我理解为什么会这样?如果是这样的话 未定义的行为,如何显示这样的输出?
是的,行为未定义,但输出不同的原因是调用约定。 ideone编译器以32位运行,这意味着参数在堆栈上传递(根据System V ABI)而不是寄存器。您可能会看到代码的反汇编显示为:
push 0
push 5
push 0
push 3
push 0
push 1
push OFFSET FLAT:.LC0
call printf
第二个代码片段不同,因为每次只传递一个参数,因此它获得正确的(即第一个)值。