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

时间:2011-07-27 20:21:20

标签: c printf

我正在使用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

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

5 个答案:

答案 0 :(得分:14)

您应该使用<inttypes.h>

中定义的宏
printf("a is %"PRIx64" & b is %"PRIx64" & c is %"PRIx64"\n",a,b,c);

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

答案 1 :(得分:10)

您需要使用正确的格式:

#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>

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

答案 2 :(得分:2)

它会在我的计算机上打印所有内容,但由于%llx期望long long unsigned int,因此有三个编译时警告。

您确定需要使用64位类型吗?所有三个十六进制代码只有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位,否则你可以在以后添加更多位。

答案 3 :(得分:1)

使用:

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

查看“inttypes.h”。

答案 4 :(得分:1)

适用于名为 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  Variable 'c' pushed on the stack as uint64

    0098: 00000000
    0094: 87654321  'b' pushed on the stack as uint64

    0090: 00000000
    008C: 12345678  'a' pushed on the stack as uint64

    0088: <pointer to format string>
    0084: <return address>

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

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

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

    00A4: ...

    00A0: 00000000

    009C: 11111111
    0098: 00000000  '%llx' reads 'c' as uint64, but from the wrong address

    0094: 87654321
    0090: 00000000  '%llx' reads 'b' as uint64, but from the wrong address

    008C: 12345678  '%x' causes printf() to read 'a' as a uint32

    0088: <pointer to format string>
    0084: <return address>

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

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