12

typedefs 的一个常见用途是使变量的“类型”能够更好地传达变量用途的概念,而无需重新定义其背后的存储结构。

但是,我也将 typedef 视为一次性更改一类变量的存储结构的一种方式。

例如,如果我定义

typedef uint32_t my_offset_t

并且有 type 的变量,my_offset_t将代码库从uint32_tto切换到charoruint64_t就像更改一行并重新编译一样简单(假设我使用sizeof了而不是硬编码的大小),除了 printf / scanf 的情况

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

谢谢!

对于任何感兴趣的人,我正在修改一个使用 16 位偏移量的 LKM 以使用 32 位偏移量,但希望它能够在必要时以最小的更改进入 64 位(或其他!)偏移量。

4

3 回答 3

9

这是一项棘手的业务,但<inttypes.h>来自 C99 及更高版本的代码显示了实现此目的的方法。

对于您定义的每个类型,您需要为自己提供一组适当的“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并且在两者上都可以干净地编译。)

于 2012-05-09T00:49:32.993 回答
7

如果您查看我之前关于 inttypes.h 的问题,您可以看到系统定义的格式说明符如何与 typedefs 一起使用(通过#define)为您的自定义类型制作自定义打印说明符。

于 2012-05-09T00:13:47.620 回答
0

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

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

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

对于这些*scanf()功能,您必须读入一个临时对象然后分配。

(这假设您的运行时库支持这些功能。)

于 2012-05-09T02:26:33.850 回答