简体   繁体   中英

Typedefs and printf format specifiers

A common use of typedefs is to enable the 'type' of a variable to convey a better idea of a variable's purpose without redefining the storage structure behind it.

However, I'm also seeing typedefs as a way to change the storage structure for a class of variables in one go.

For example, if I define

typedef uint32_t my_offset_t

and have variables of the type my_offset_t , switching the code-base from uint32_t to char or uint64_t is as simple as changing one line and recompiling (assuming I've used sizeof rather than hard-coded sizes), except in the case of printf / scanf .

Is there a way to swap format-specifiers according to the type in some easy way, without wrapper functions around printf / scanf , if-elses, or ifdefs?

Thanks!

For anyone interested, I'm modifying an LKM that used 16-bit offsets to work with 32-bit offsets, but want it to be able to go to 64-bit (or something else!) offsets if necessary with minimal changes.

It's a tricky business, but the <inttypes.h> from C99 and later shows the way to do it.

For each of your defined types, you need to provide yourself with an appropriate set of 'PRI' and 'SCN' macros, being careful to avoid standardized namespace.

For example, you might use XYZ as a project-specific prefix, and produce:

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

and the SCN equivalents. Further, you'd define these in terms of the the equivalent macros for the base type, so:

#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

In your code, you build your format strings using the XYZ_PRIx_my_offset_t macros:

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

If you subsequently need to change everything to 64-bit, you edit the typedef and the macro definitions appropriately, and the rest of the code remains 'unchanged'. If you're really careful, you can get pretty close to completely unchanged.

Make sure you compile on both 32-bit and 64-bit systems with lots of warnings set. GCC will not warn about non-problems on your current platform, but they may show up on the other. (I just fixed some code that was clean on 64-bit but unclean for 32-bit; it now uses a macro like XYZ_PRId_int4 instead of %d and compiles cleanly on both.)

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

Another solution is to convert to and from intmax_t for signed types and uintmax_t for unsigned types. For example:

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

will work correctly if n is of any unsigned type.

For the *scanf() functions, you'd have to read into a temporary object and then assign.

(This assumes your runtime library supports these features.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM