C++ 为什么I64d“;在同一格式字符串中多次使用时是否会给出奇怪的输出?
当我在codeforces上解决编程问题时,我发现在同一格式字符串中多次使用格式说明符“%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
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 printfI
表示“使用替代输出数字”,而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 printfI
表示“使用替代输出数字”,而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