为什么“%I64d”在同一格式字符串中多次使用时会给出奇怪的输出?

时间:2016-12-30 10:51:26

标签: c++ c

当我解决代码强制的编程问题时,我发现格式说明符“%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

请帮助我理解为什么会这样?如果这是未定义的行为,如何显示这样的输出?我怎样才能理解有时出现这种意外输出的原因?

2 个答案:

答案 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

第二个代码片段不同,因为每次只传递一个参数,因此它获得正确的(即第一个)值。