C++ 为什么I64d“;在同一格式字符串中多次使用时是否会给出奇怪的输出?

C++ 为什么I64d“;在同一格式字符串中多次使用时是否会给出奇怪的输出?,c++,c,C++,C,当我在codeforces上解决编程问题时,我发现在同一格式字符串中多次使用格式说明符“%I64d”时,如下所示: long long int a, b, c; a = 1, b = 3, c = 5; printf("%I64d %I64d %I64d\n", a, b, c); 输出是 1

当我在codeforces上解决编程问题时,我发现在同一格式字符串中多次使用格式说明符“%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链接,可查看上述代码片段的实际操作:


请帮助我理解为什么会发生这种情况?如果这是未定义的行为,如何显示这样的输出?当有时显示这些意外输出时,我如何理解原因?

格式字符串
%I64d
printf()
要求堆栈上有一个4字节的数字,因为GNU printf
I
表示“使用替代输出数字”,而
64
表示“填充到64个字符”。剩余的
d
表示有符号32位整数

但是您正在推8字节的数字,因为
a、b、c
属于
long
类型

数字低于2^32,因此在堆栈上可以看到(以4字节为单位)

printf仅解释前3个数字,其余数字将被丢弃。使用
%lld
时,
printf()
将堆栈数据正确解释为8字节数字

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

是的,行为未定义,但不同输出的原因是调用约定。ideone编译器以32位运行,这意味着参数在堆栈上传递(根据System V ABI),而不是在寄存器上传递。您可能会看到代码的分解如下所示:

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

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

%I64d
是Microsoft ism。将
%lld
(即elldee)与
%I64d
printf一起使用,堆栈上需要一个4字节的数字。但是你推的是8字节的数字,因为a/b/c是长的。数字低于2^32,因此在堆栈上(以4字节的步骤)可以看到“1 0 3 0 5 0”。printf只读取前3个数字,其余数字将被丢弃。当您使用
%lld
时,printf将堆栈数据正确地解释为8字节的数字。@ctx为什么
%I64d
需要一个4字节的数字?@CodyGray With gnu printf
I
表示“使用替代输出数字”,而
64
表示“填充到64个字符”。剩余的
d
代表有符号的32位整数。编译器没有发出有关
printf(“%I64d%I64d%I64d\n”,a,b,c)的警告吗?您可能需要检查编译器的警告级别是否设置为最高级别-节省时间。
    push    0
    push    5
    push    0
    push    3
    push    0
    push    1
    push    OFFSET FLAT:.LC0
    call    printf