4

我有一个代码库,旨在在没有警告的情况下编译并在多种架构上运行而不会出现任何故障,所有 x86:MSDOS、Windows 32 控制台模式、Windows 32 GUI 模式、Linux 32 和 Linux 64。

在添加对 Linux 64 的支持之前,这很容易。几乎所有数据都被声明int为 BYTE、WORD 和 DWORD 的 typedef 中的一个或来自 typedef:

typedef unsigned char   BYTE;
typedef unsigned short  WORD;
typedef unsigned long   DWORD;

添加 64 位 gcc 支持后,DWORD 需要稍微调整以保持为 32 位值,因为它表示存储的数据:

// to compile DWORDs as 32 bits on 64-bit machines:
#if __x86_64__
 typedef unsigned int    DWORD;
#else
 typedef unsigned long   DWORD;
#endif

这适用于所有环境:

DWORD   data;
printf ("%lu", data);

但是,gcc -Wall现在抱怨格式转换:

warning: format ‘%ld’ expects argument of type ‘long int’, but argument
         1 has type ‘DWORD {aka unsigned int}’ [-Wformat]

由于这段代码的格式非常广泛——数千行输出格式——我宁愿不改造特定类型的格式化程序。使用修饰符回答了z类似的问题:

printf ("%zu", data);

但这使得 MSDOS 和 Win32 控制台上的 Turbo C 做了一些奇怪的事情:它将转换规范显示%zu为输出,而不是转换任何东西。

有没有一种更简洁的方法来处理类型的可变性,这种方式与 printf 的粒度和基本数据类型相匹配?

4

1 回答 1

4

我认为你最不坏的可用选择是从概念上借用<inttypes.h>

#ifdef _LP64
#define PRIdword  "d"
#define PRIudword "u"
#else
#define PRIdword  "ld"
#define PRIudword "lu"
#endif

接着

DWORD data;
printf("%"PRIdword, data);

这利用了所有符合 C90 的编译器都应该支持的字符串常量连接。请注意,要测试的正确宏是_LP64,而不是__x86_64__;这样,当您移植到其他一些 LP64 系统或 Linux/x86-64(32 位指针、宽寄存器)的闪亮的新“x32”模式时,它就会正常工作。

投资于<stdint.h>类型的批发转换可能不是一个坏主意,但这不会让你摆脱这种事情,你只是在写

int32_t data;
printf("%"PRId32, data);

相反,据我所知,大多数 Windows 编译器仍然没有<inttypes.h>,叹息。

如果您想知道,%宏不在宏内,因此您可以根据需要放入格式调整器:

printf("%-32"PRIdword, data);
于 2013-06-05T20:51:57.167 回答