Convert% ld format for portability

I have a code base that is designed to compile without warnings and run without any glitches on several architectures, all x86 console modes: MSDOS, Windows 32, Windows 32 GUI mode, Linux 32 and Linux 64.

Prior to adding Linux 64 support, this was easy. Almost all data was declared as int or from typedefs for BYTE, WORD, and DWORD:

 typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; 

After adding 64-bit gcc support, DWORD needed a little tweaking to stay as a 32-bit value, since it represented the stored data:

 // to compile DWORDs as 32 bits on 64-bit machines: #if __x86_64__ typedef unsigned int DWORD; #else typedef unsigned long DWORD; #endif 

And it worked well in all environments:

 DWORD data; printf ("%lu", data); 

However, gcc -Wall now complains about format conversion:

 warning: format '%ld' expects argument of type 'long int', but argument 1 has type 'DWORD {aka unsigned int}' [-Wformat] 

Due to the extensive formatting, this code does indeed contain thousands of lines of formatting output: I would prefer not to modify the formatter of a certain type. A similar question was answered using the z modifier :

 printf ("%zu", data); 

But this forces Turbo C on the MSDOS and Win32 consoles to do something odd: it shows the %zu conversion specification as output instead of converting something.

Is there a cleaner way to handle type volatility in a way related to printf grains and basic data types?

+4
source share
1 answer

I think your least bad option is to borrow conceptually from <inttypes.h> :

 #ifdef _LP64 #define PRIdword "d" #define PRIudword "u" #else #define PRIdword "ld" #define PRIudword "lu" #endif 

and then

 DWORD data; printf("%"PRIdword, data); 

This uses the string constant concatenation that all C90 compatible compilers must support. Note that the correct macro to check is _LP64 , not __x86_64__ ; that way, it will just work when you switch to a port for some other LP64 system or to the shiny new "x32" Linux / x86-64 mode (32-bit pointers, wide registers).

It might be nice to invest in bulk conversion to <stdint.h> types, but that won’t save you from this kind of thing, you just write

 int32_t data; printf("%"PRId32, data); 

instead, and as far as I know, most Windows compilers still don't have <inttypes.h> , sigh.

In case you are interested, % not inside the macro, so you can put formatting controls if you want:

 printf("%-32"PRIdword, data); 
+3
source

Source: https://habr.com/ru/post/1484726/


All Articles