typedef的一个常见用途是启用变量的“类型”以更好地了解变量的用途,而无需重新定义其后面的存储结构。
但是,我也看到typedef是一种改变一类变量存储结构的方法。
例如,如果我定义
typedef uint32_t my_offset_t
并且拥有my_offset_t
类型的变量,将代码库从uint32_t
切换到char
或uint64_t
就像更改一行并重新编译一样简单(假设我使用sizeof
而不是硬编码的尺寸),除了printf / scanf 之外。
有没有办法根据类型以一种简单的方式交换格式说明符,没有printf
/ scanf
,if-elses或ifdefs的包装函数?
谢谢!
对于任何有兴趣的人,我正在修改一个使用16位偏移的LKM来处理32位偏移,但是希望它能够转到64位(或其他东西!)偏移量只需要很少的改动就可以了。
答案 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()
函数,您必须读入临时对象然后分配。
(这假设您的运行时库支持这些功能。)