Question

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.

Was it helpful?

Solution

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.)

OTHER TIPS

If you look at my earlier question on inttypes.h you can see how system defined format specifiers could be used in concert with typedefs (via #define) to make custom print specifiers for your custom types.

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.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top