为什么“%I64d”在相同格式字符串中多次使用时会输出奇怪的输出?
问题描述:
当我解决上codeforces一个规划问题,我发现,在格式说明“%I64d号”,使用了相同的格式字符串多次这样的:为什么“%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
请帮助我了解为什么发生这种情况?如果这是未定义的行为,如何显示这样的输出?有时会出现这种意想不到的结果,我怎么能理解这些原因?
答
随着格式字符串%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
只有第3个数字由printf的解释,其余的将被丢弃。当您使用%lld
时,printf()
将堆栈数据正确解释为8字节数字。
答
请帮我理解为什么会发生这种情况?如果这是 未定义的行为,如何显示这样的输出?
是的,行为是不确定的,但不同的输出的原因是由于调用约定。 ideone编译器运行在32位,这意味着参数在栈上传递(根据System V ABI)而不是寄存器。您可能会看到的代码是dissassembly节目,如:
push 0
push 5
push 0
push 3
push 0
push 1
push OFFSET FLAT:.LC0
call printf
第二个代码段是不同的,因为你通过每次只有一个参数,因此它的正确的(即第一个)值。
'%I64d'是Microsoft的主义。使用'%lld'(这是ell-ell-dee) –
谢谢,但是当我尝试使用%lld提交时,codeforces会引发警告。我可以使用%lld,但我很好奇为什么以及如何在上述情况下显示这样的输出。 –
使用'%I64d' printf需要在堆栈上有一个4字节的数字。但是你正在推送8字节数字,因为a/b/c是'long long'。数字低于2^32,因此在堆栈中您看到(以4个字节为步长)“1 0 3 0 5 0”。只有前3个数字被printf读取,其余的被丢弃。当你使用'%lld'时,printf正确地将堆栈数据解释为8字节数字。 – Ctx