Typedef和printf格式说明符

时间:2012-05-09 00:10:34

标签: c typedef format-specifiers

typedef的一个常见用途是启用变量的“类型”以更好地了解变量的用途,而无需重新定义其后面的存储结构。

但是,我也看到typedef是一种改变一类变量存储结构的方法。

例如,如果我定义

typedef uint32_t my_offset_t

并且拥有my_offset_t类型的变量,将代码库从uint32_t切换到charuint64_t就像更改一行并重新编译一样简单(假设我使用sizeof而不是硬编码的尺寸),除了printf / scanf 之外。

有没有办法根据类型以一种简单的方式交换格式说明符,没有printf / scanf,if-elses或ifdefs的包装函数?

谢谢!

对于任何有兴趣的人,我正在修改一个使用16位偏移的LKM来处理32位偏移,但是希望它能够转到64位(或其他东西!)偏移量只需要很少的改动就可以了。

3 个答案:

答案 0 :(得分: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这样的宏,并在两者上干净地编译。)

答案 1 :(得分:7)

如果查看我的earlier question on inttypes.h,您可以看到系统定义的格式说明符如何与typedef(通过#define)一起使用,以便为您的自定义类型制作自定义打印说明符。

答案 2 :(得分:0)

另一种解决方案是针对签名类型转换为intmax_t,针对无符号类型转换为uintmax_t。例如:

printf("%ju\n", (uintmax_t)n);
如果n是任何无符号类型,

将正常工作。

对于*scanf()函数,您必须读入临时对象然后分配。

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