类型定义和printf格式说明符

12

typedef 的一个常见用途是使变量的 '类型' 能够更好地传达变量的目的,而不必重新定义其后面的存储结构。

然而,我也看到 typedef 作为一种在一次性更改类别的变量的存储结构的方法。

例如,如果我定义

typedef uint32_t my_offset_t

如果我的变量类型是my_offset_t,那么将代码从uint32_t更改为charuint64_t只需要更改一行代码并重新编译(假设我使用了sizeof而不是硬编码的大小),除了printf / scanf之外

有没有一种简单的方法根据类型交换格式说明符,而无需在printf/scanf周围添加包装函数、if-elses或ifdefs?

谢谢!

对于任何感兴趣的人,我正在修改一个LKM,该LKM使用16位偏移量来适用于32位偏移量,但希望它能够在最小更改的情况下适用于64位(或其他)偏移量。

3个回答

9

这是一项棘手的业务,但C99及以后的<inttypes.h>库为此提供了解决方案。

对于您定义的每种类型,您需要提供一个适当的“PRI”和“SCN”宏集,注意避免标准化命名空间冲突。

例如,您可以使用XYZ作为项目特定前缀,并生成:

XYZ_PRIx_my_offset_t
XYZ_PRId_my_offset_t
XYZ_PRIX_my_offset_t
XYZ_PRIu_my_offset_t
XYZ_PRIo_my_offset_t

以及 SCN 的等效项。此外,你需要根据基本类型的等效宏来定义它们,因此:

#define XYZ_PRIx_my_offset_t PRIx32
#define XYZ_PRId_my_offset_t PRId32
#define XYZ_PRIX_my_offset_t PRIX32
#define XYZ_PRIu_my_offset_t PRIu32
#define XYZ_PRIo_my_offset_t PRIo32

在您的代码中,您使用XYZ_PRIx_my_offset_t宏来构建格式字符串:

printf("Offset: 0x%.8" XYZ_PRIX_my_offset_t "\n", my_offset_value);

如果您随后需要将一切更改为64位,您可以适当编辑typedef和宏定义,其余代码保持“不变”。如果您非常小心,就可以接近完全不变。
请确保在32位和64位系统上编译时设置了大量警告。 GCC不会对当前平台上的非问题发出警告,但它们可能会显示在另一个平台上。(我刚刚修复了一些代码,这些代码在64位上很干净,但在32位上却不干净;现在它使用类似于XYZ_PRId_int4的宏而不是%d,并且在两者上都可以编译成功。)

7

如果您查看我关于inttypes.h的早期问题,您可以看到如何将系统定义的格式说明符与typedef(通过#define)结合使用,为您的自定义类型创建自定义打印说明符。


谢谢你的回答 :) 不过我接受了另一个回答,因为它更完整,以防其他人对这个问题感兴趣。 - Vanwaril

0

另一种解决方案是将有符号类型转换为intmax_t,将无符号类型转换为uintmax_t。例如:

printf("%ju\n", (uintmax_t)n);

如果n是任何无符号类型,则将正常工作。

对于*scanf()函数,您需要读入一个临时对象,然后再进行赋值操作。

(这需要您的运行库支持这些功能。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接