I
ImpalerCore
One of the pet peeves of mine for a long time is printing size_t
values, because C99 has the nice little 'z' modifier, but in the
compiler I use for embedded work, these C99 features is not
supported. In those situations, the recommendation is to cast the
size_t value to unsigned long, and use %lu. The issue is that there
are two different source styles for the two compiler environments, and
I'd like to make a single style work for both compiler standards. Of
course one could resort to use %lu and casting in both environments,
but I don't like it.
The two styles clash because I am writing a library for which I'd like
to maintain support for C90 and C99 compilers, and many of the
examples use size_t variables, either directly or indirectly through a
library function's return value or argument. I don't want to maintain
two separate examples just because the rules for printing a size_t
differ.
I currently have a wrapper for <stdint.h> and <inttypes.h> that I use
to define C90 versions of the intN_t and uintN_t types, as well as
their fprintf macro format specifiers like PRIu32. If one lacks a
native <inttypes.h> header file, one can still manually define them by
looking at <limits.h>.
\code snippet
.... stdint.h definitions above like ...
#define INT32_MAX (2147483647L)
....
#if defined(_MSC_VER) || defined(_WIN32)
# define PRId32 "I32d"
# define PRIi32 "I32i"
#else
# if (INT32_MAX == LONG_MAX)
# define PRId32 "ld"
# define PRIi32 "id"
# elif (INT32_MAX == INT_MAX)
# define PRId32 "d"
# define PRIi32 "i"
# elif (INT32_MAX == SHRT_MAX)
# define PRId32 "hd"
# define PRIi32 "hi"
# else
# error "Platform not supported"
# endif
#endif
\endcode
One way to provide a single viable method to format a size_t integer
is to create an <inttypes.h> compatible fprintf macro format
specifier, let's call it PRI[ouxX]SIZE. If C99 is present, one can
simply defer to use "z" as the leading modifier, but if it's not
present, one can again use <limits.h> to determine the correct
modifier to apply.
\code snippet
#if (defined(__STDC__) && defined(__STDC_VERSION__))
# if (__STDC__ && __STDC_VERSION__ >= 199901L)
# define PRIoSIZE "zo"
# define PRIuSIZE "zu"
# define PRIxSIZE "zx"
# define PRIXSIZE "zX"
# endif
#else
/* ULLONG_MAX is defined in my wrapper if 64-bit integer extensions
are detected, even if it's not a C99 compiler. */
# if defined(ULLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
# define PRIoSIZE "llo"
# define PRIuSIZE "llu"
# define PRIxSIZE "llx"
# define PRIXSIZE "llX"
# elif (SIZE_MAX == ULONG_MAX)
# define PRIoSIZE "lo"
# define PRIuSIZE "lu"
# define PRIxSIZE "lx"
# define PRIXSIZE "lX"
# elif (SIZE_MAX == UINT_MAX)
# define PRIoSIZE "o"
# define PRIuSIZE "u"
# define PRIxSIZE "x"
# define PRIXSIZE "X"
# elif (SIZE_MAX == USHRT_MAX)
# define PRIoSIZE "ho"
# define PRIuSIZE "hu"
# define PRIxSIZE "hx"
# define PRIXSIZE "hX"
# else
# error "Platform not supported"
# endif
#endif
\endcode
Then in theory, one can use the following to print a size_t value in
either C90 or C99.
\code snippet
#include <stdio.h>
#include "my_inttypes.h"
int main( void )
{
printf( "sizeof int = %" PRIuSIZE "\n", sizeof (int) );
return 0;
}
\endcode
The only kicker is that SIZE_MAX is not defined in C90, so one must
either rely on an auto-configuration script to detect SIZEOF_SIZE_T
that you can infer SIZE_MAX from, or worse have a human define it
manually. Definitions like ((size_t)-1) don't seem to work with the
preprocessor well.
I must say that I find the idea of PRIuSIZE and friends tempting, just
to have a uniform method of printing size_t values in library API
examples that work in C90 and C99, and hopefully C1X. I'm not
familiar with the history of the fprintf macro specifiers, so I wonder
why PRIuSIZE and friends were not included, when it's an obvious
candidate due to a lack of an exact modifier to a format specifier.
In my opinion, it's much easier to define a stdint.h/inttypes.h
wrapper for a C90 compiler and use PRIuSIZE than to create/modify a
printf implementation to accept %zu.
Even if I do like and choose to use my own PRIuSIZE creation in my
library examples, I imagine it's likely to get flak from it being
unidiomatic. Am I destined to cast my size_t values to (unsigned
long) forever?
Just for my curiosity's sake, any reason why stdint.h and inttypes.h
were separated in the first place? After looking at inttypes.h, it
doesn't really define any integer types as it's name implies, mostly
format specifiers. It seems logical to just graft inttypes.h into
stdint.h and put it all in one place.
Thanks for any feedback,
John D.
values, because C99 has the nice little 'z' modifier, but in the
compiler I use for embedded work, these C99 features is not
supported. In those situations, the recommendation is to cast the
size_t value to unsigned long, and use %lu. The issue is that there
are two different source styles for the two compiler environments, and
I'd like to make a single style work for both compiler standards. Of
course one could resort to use %lu and casting in both environments,
but I don't like it.
The two styles clash because I am writing a library for which I'd like
to maintain support for C90 and C99 compilers, and many of the
examples use size_t variables, either directly or indirectly through a
library function's return value or argument. I don't want to maintain
two separate examples just because the rules for printing a size_t
differ.
I currently have a wrapper for <stdint.h> and <inttypes.h> that I use
to define C90 versions of the intN_t and uintN_t types, as well as
their fprintf macro format specifiers like PRIu32. If one lacks a
native <inttypes.h> header file, one can still manually define them by
looking at <limits.h>.
\code snippet
.... stdint.h definitions above like ...
#define INT32_MAX (2147483647L)
....
#if defined(_MSC_VER) || defined(_WIN32)
# define PRId32 "I32d"
# define PRIi32 "I32i"
#else
# if (INT32_MAX == LONG_MAX)
# define PRId32 "ld"
# define PRIi32 "id"
# elif (INT32_MAX == INT_MAX)
# define PRId32 "d"
# define PRIi32 "i"
# elif (INT32_MAX == SHRT_MAX)
# define PRId32 "hd"
# define PRIi32 "hi"
# else
# error "Platform not supported"
# endif
#endif
\endcode
One way to provide a single viable method to format a size_t integer
is to create an <inttypes.h> compatible fprintf macro format
specifier, let's call it PRI[ouxX]SIZE. If C99 is present, one can
simply defer to use "z" as the leading modifier, but if it's not
present, one can again use <limits.h> to determine the correct
modifier to apply.
\code snippet
#if (defined(__STDC__) && defined(__STDC_VERSION__))
# if (__STDC__ && __STDC_VERSION__ >= 199901L)
# define PRIoSIZE "zo"
# define PRIuSIZE "zu"
# define PRIxSIZE "zx"
# define PRIXSIZE "zX"
# endif
#else
/* ULLONG_MAX is defined in my wrapper if 64-bit integer extensions
are detected, even if it's not a C99 compiler. */
# if defined(ULLONG_MAX) && (SIZE_MAX == ULLONG_MAX)
# define PRIoSIZE "llo"
# define PRIuSIZE "llu"
# define PRIxSIZE "llx"
# define PRIXSIZE "llX"
# elif (SIZE_MAX == ULONG_MAX)
# define PRIoSIZE "lo"
# define PRIuSIZE "lu"
# define PRIxSIZE "lx"
# define PRIXSIZE "lX"
# elif (SIZE_MAX == UINT_MAX)
# define PRIoSIZE "o"
# define PRIuSIZE "u"
# define PRIxSIZE "x"
# define PRIXSIZE "X"
# elif (SIZE_MAX == USHRT_MAX)
# define PRIoSIZE "ho"
# define PRIuSIZE "hu"
# define PRIxSIZE "hx"
# define PRIXSIZE "hX"
# else
# error "Platform not supported"
# endif
#endif
\endcode
Then in theory, one can use the following to print a size_t value in
either C90 or C99.
\code snippet
#include <stdio.h>
#include "my_inttypes.h"
int main( void )
{
printf( "sizeof int = %" PRIuSIZE "\n", sizeof (int) );
return 0;
}
\endcode
The only kicker is that SIZE_MAX is not defined in C90, so one must
either rely on an auto-configuration script to detect SIZEOF_SIZE_T
that you can infer SIZE_MAX from, or worse have a human define it
manually. Definitions like ((size_t)-1) don't seem to work with the
preprocessor well.
I must say that I find the idea of PRIuSIZE and friends tempting, just
to have a uniform method of printing size_t values in library API
examples that work in C90 and C99, and hopefully C1X. I'm not
familiar with the history of the fprintf macro specifiers, so I wonder
why PRIuSIZE and friends were not included, when it's an obvious
candidate due to a lack of an exact modifier to a format specifier.
In my opinion, it's much easier to define a stdint.h/inttypes.h
wrapper for a C90 compiler and use PRIuSIZE than to create/modify a
printf implementation to accept %zu.
Even if I do like and choose to use my own PRIuSIZE creation in my
library examples, I imagine it's likely to get flak from it being
unidiomatic. Am I destined to cast my size_t values to (unsigned
long) forever?
Just for my curiosity's sake, any reason why stdint.h and inttypes.h
were separated in the first place? After looking at inttypes.h, it
doesn't really define any integer types as it's name implies, mostly
format specifiers. It seems logical to just graft inttypes.h into
stdint.h and put it all in one place.
Thanks for any feedback,
John D.