为什么C中的printf()不能同时打印两个64位值?

我正在研究一个32位系统。 当我尝试在单个printf中打印多个64位值时,它无法再打印任何值(即第2,第3 ……)变量值。

例:

uint64_t a = 0x12345678; uint64_t b = 0x87654321; uint64_t c = 0x11111111; printf("a is %llx & b is %llx & c is %llx",a,b,c); 

为什么这个printf不能打印所有值?

我正在修改我的问题

 printf("a is %x & b is %llx & c is %llx",a,b,c); 

通过这样做的结果是:a是12345678&b是8765432100000000&c是1111111100000000

如果我没有正确打印一个值,那为什么其他的价值才会变化?

您需要使用正确的格式:

 #include  #include  #include  int main(void) { uint64_t a = 0x12345678; uint64_t b = 0x87654321; uint64_t c = 0x11111111; printf("a is %#" PRIx64 " & b is %#" PRIx64 " & c is %#" PRIx64 "\n", a, b, c); return EXIT_SUCCESS; } 

输出:

 a is 0x12345678 & b is 0x87654321 & c is 0x11111111 

您应该使用定义的宏

 printf("a is %"PRIx64" & b is %"PRIx64" & c is %"PRIx64"\n",a,b,c); 

这很难看,但它很便携。 这是在C99中引入的,因此您需要符合C99的编译器。

它将它们打印在我的计算机上,但是有三个编译时警告,因为%llx需要一个long long unsigned int

你确定你需要使用64位类型吗? 所有三个hex代码只有32位。 也许你可以只使用32位并执行:

 unsigned int a = 0x12345678; unsigned int b = 0x87654321; unsigned int c = 0x11111111; printf("a is %x & b is %x & c is %x",a,b,c); 

(或者使用相当于32位unsigned int的stdint)

除非你需要它们是64位,否则你可以在以后添加更多位。

使用:

 "%lli" for int64_t "%llu" for uint64_t "%llx" for hex "%llX" for HEX 

看看里面的“inttypes.h”。

适用于名为Stack Overflow的论坛,意外printf()输出的原因是堆栈错位。 %x转换规范与函数参数a之间的大小不匹配会导致未对齐。

编译语句时

 printf("a is %x & b is %llx & c is %llx",a,b,c); 

编译器生成机器代码,以从右到左的顺序推送堆栈上的函数参数。

编译器使用变量声明而不是格式字符串来确定堆栈上每个参数的数据大小(可能除了生成警告之外)。 在x86 CPU中(与大多数机器一样),堆栈指针随着每次推送而递减。 当输入printf()库函数时,堆栈因此具有以下布局:

     00A4:......

     00A0:00000000
     009C:11111111变量'c'作为uint64推入堆栈

     0098:00000000
     0094:87654321'b'作为uint64推入堆栈

     0090:00000000
     008C:12345678'a'作为uint64推入堆栈

     0088:<格式化字符串的指针>
     0084:<返回地址>

对于此示例,堆栈顶部地址0084是任意的。

由于所有三个变量都声明为uint64_t ,因此编译后的代码将这些变量作为64位值推送到堆栈上。 对于像x86 CPU这样的小端机器,每个uint64值的高字节最终都在较高的地址中。

printf()的实现使用格式字符串来确定堆栈上参数的数量和大小。 与编译器不同, printf()接收有关原始变量声明的信息。 第一个转换规范是%x ,因此printf()期望a是32位值,因此, printf()解析堆栈布局如下:

     00A4:......

     00A0:00000000

     009C:11111111
     0098:00000000'%llx'将'c'读作uint64,但来自错误的地址

     0094:87654321
     0090:00000000'%llx'将'b'读作uint64,但来自错误的地址

     008C:12345678'%x'导致printf()将'a'作为uint32读取

     0088:<格式化字符串的指针>
     0084:<返回地址>

堆栈错位解释了为什么按预期打印12345678,但bc已经有效地左移32位到8765432100000000和1111111100000000。

更正第一个%x转换规范或将参数a转换为uint32应该可以解决问题。