I am currently working on a software project in C which has to run on a variety of platforms. I try to remain as close to the C90 standard as possible, but need some commonly supported extensions like stdint.h and an unsigned long long type. I deliberately do not want to "fall back" to the C99 standard since some of the compilers that I use do not support all C99 features like mixed declarations and code etc.
Thus, I currently compile all my code with gcc on my (64-bit Ubuntu) development machine with -Wall -Wextra -pedantic -std=gnu90
(not C90 due to my use of unsigned long long etc. as described above) to address all non-format-compliant code parts. So far, I could adapt my code to get rid of all warnings but one: I cannot find a proper (printf) format for size_t that does not yield a warning from gcc. Consider the following example code which illustrates most of the things that I tried:
#include <stdint.h>
#include <stdio.h>
int main()
{
printf("%zu", sizeof(int)); /* C99 format specifier for size_t */
printf("%u", sizeof(int)); /* Treat size_t as unsigned int */
printf("%lu", sizeof(int)); /* Treat size_t as unsigned long int (only works when size_t is "typedef"ed to unsigned long int) */
return 0;
}
When compiled with -Wall -Wextra -pedantic -std=gnu90
, I get warnings for the first two lines:
test.c:6:3: warning: ISO C90 does not support the ‘z’ gnu_printf length modifier [-Wformat=] test.c:7:3: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
Although I do not get a warning for the third line, this is only the case on my development system. On other systems, specifically on those where size_t is some "custom" type or not "typedef"ed as unsigned long long, there will still be a warning.
I am well aware that there is no format specifier for size_t in C90, but that there is one in C99. However, I thought that setting -std=gnu90
would give me the 'z' format specifier, but that assumption turned out to be incorrect.
Since I could not get rid of the warning(s), I tried to define a format specifier with some preprocessor definitions like this:
#include <inttypes.h>
#include <stdio.h>
#ifdef __GNUC__
#define GLUE(x, y, z) x##y##z
#define GLUE_FORMAT(prefix, size) GLUE(PRI, prefix, size)
#define UINT_FORMAT(size) GLUE_FORMAT(u, size)
#define SIZE_T_FORMAT UINT_FORMAT(__SIZEOF_SIZE_T__)
#else /* C99 fall-back */
#define SIZE_T_FORMAT "zu"
#endif
int main()
{
printf("%" SIZE_T_FORMAT, sizeof(int));
return 0;
}
I thought that this should give me the proper format specifier, the only constraint being that size_t is unsigned (which it is on all my target platforms so far). However, that does not work either:
test.c:15:3: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘long unsigned int’ [-Wformat=]
Is there any way, given the constraints, to overcome this warning (or to find a more elegant solution without resorting to -std=c99
)?
__SIZEOF_SIZE_T__
come from?grep __SIZEOF_SIZE_T__ /usr/include/ -rw
on my recent Debian gives me nothing ... :-S – alk%lu
and cast the result of the sizeof expression tounsigned long
. – John Bode