2016-12-30 46 views
4

当我解决上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

请帮助我了解为什么发生这种情况?如果这是未定义的行为,如何显示这样的输出?有时会出现这种意想不到的结果,我怎么能理解这些原因?

+6

'%I64d'是Microsoft的主义。使用'%lld'(这是ell-ell-dee) –

+0

谢谢,但是当我尝试使用%lld提交时,codeforces会引发警告。我可以使用%lld,但我很好奇为什么以及如何在上述情况下显示这样的输出。 –

+2

使用'%I64d' printf需要在堆栈上有一个4字节的数字。但是你正在推送8字节数字,因为a/b/c是'long long'。数字低于2^32,因此在堆栈中您看到(以4个字节为步长)“1 0 3 0 5 0”。只有前3个数字被printf读取,其余的被丢弃。当你使用'%lld'时,printf正确地将堆栈数据解释为8字节数字。 – Ctx

回答

10

随着格式字符串%I64dprintf()预计堆栈上的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字节数字。

3

请帮我理解为什么会发生这种情况?如果这是 未定义的行为,如何显示这样的输出?

是的,行为是不确定的,但不同的输出的原因是由于调用约定。 ideone编译器运行在32位,这意味着参数在栈上传递(根据System V ABI)而不是寄存器。您可能会看到的代码是dissassembly节目,如:

push 0 
    push 5 
    push 0 
    push 3 
    push 0 
    push 1 
    push OFFSET FLAT:.LC0 
    call printf 

第二个代码段是不同的,因为你通过每次只有一个参数,因此它的正确的(即第一个)值。

相关问题