【问题标题】:%ld format conversion for portability%ld 格式转换以实现可移植性
【发布时间】:2013-06-06 12:34:37
【问题描述】:

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

在添加对 Linux 64 的支持之前,这很容易。几乎所有数据都被声明为 int 或来自 BYTE、WORD 和 DWORD 的 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]

由于此代码的格式非常广泛——数千行输出格式——我宁愿不改造特定类型的格式化程序。一个类似的问题是answered by using the z modifier

printf ("%zu", data);

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

是否有一种更简洁的方法来处理类型的可变性,以符合 printf 的粒度和基本数据类型?

【问题讨论】:

标签: c++ x86 printf 32bit-64bit 16-bit


【解决方案1】:

我认为你最不坏的可用选项是从概念上借用<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);

【讨论】:

  • 是的。我会做这样的事情。在仔细重新评估使用的类型后,可以将一半多一点更改为intlong。只有几百个不是那么容易通用的,所以我会将它们更改为使用%s 的格式,并大量转换为字符串函数,在参数类型上重载。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-16
  • 2018-05-30
  • 1970-01-01
  • 2016-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多