%ld 格式转换以实现可移植性

wal*_*lyk 4 c++ x86 printf 16-bit 32bit-64bit

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

\n\n

在添加对 Linux 64 的支持之前,这很容易。几乎所有数据都被声明为intBYTE、WORD 和 DWORD 的类型定义:

\n\n
typedef unsigned char   BYTE;\ntypedef unsigned short  WORD;\ntypedef unsigned long   DWORD;\n
Run Code Online (Sandbox Code Playgroud)\n\n

添加 64 位 gcc 支持后,DWORD 需要进行一些调整才能保持 32 位值,因为它表示存储的数据:

\n\n
// to compile DWORDs as 32 bits on 64-bit machines:\n#if __x86_64__\n typedef unsigned int    DWORD;\n#else\n typedef unsigned long   DWORD;\n#endif\n
Run Code Online (Sandbox Code Playgroud)\n\n

这在所有环境下都运行良好:

\n\n
DWORD   data;\nprintf ("%lu", data);\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
warning: format \xe2\x80\x98%ld\xe2\x80\x99 expects argument of type \xe2\x80\x98long int\xe2\x80\x99, but argument\n         1 has type \xe2\x80\x98DWORD {aka unsigned int}\xe2\x80\x99 [-Wformat]\n
Run Code Online (Sandbox Code Playgroud)\n\n

由于此代码进行了广泛的格式化(数千行输出格式化),我宁愿不改进特定于类型的格式化程序。使用z修饰符回答了类似的问题:

\n\n
printf ("%zu", data);\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

是否有一种更清晰的方法来以符合 printf 和基本数据类型的方式处理类型的可变性?

\n

zwo*_*wol 5

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

#ifdef _LP64
#define PRIdword  "d"
#define PRIudword "u"
#else
#define PRIdword  "ld"
#define PRIudword "lu"
#endif
Run Code Online (Sandbox Code Playgroud)

进而

DWORD data;
printf("%"PRIdword, data);
Run Code Online (Sandbox Code Playgroud)

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

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

int32_t data;
printf("%"PRId32, data);
Run Code Online (Sandbox Code Playgroud)

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

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

printf("%-32"PRIdword, data);
Run Code Online (Sandbox Code Playgroud)


归档时间:

查看次数:

14026 次

最近记录:

12 年,3 月 前