Is it safe to cast size_t to unsigned long int?

c c89
August Karlstrom picture August Karlstrom · Nov 29, 2017 · Viewed 9.4k times · Source

I need a portable way to print the value of a variable n of type size_t. Since I use ANSI C89 I cannot use the z length modifier. My current approach is to cast the value to long unsigned int:

printf("%lu\n", (long unsigned int) n);

Provided that size_t is defined as either unsigned int or long unsigned int I can't see how this would fail. Is the cast safe?

Answer

user955340 picture user955340 · Nov 29, 2017

In C89, size_t is defined as an unsigned integer type. Unlike future standards, C89 defines what the list of unsigned integer types are as the following:

  • unsigned char
  • unsigned short
  • unsigned int
  • unsigned long

As such, size_t in C89 will never be larger than unsigned long, and therefore the cast is always safe - both in that it will not cause any undefined behaviour and in that it will always be large enough to hold the value in entirety.

Worth noting; the C89 standard states: "A conforming implementation may have extensions (including additional library functions), provided they do not alter the behavior of any strictly conforming program" Meaning that no extension could change this behaviour - while still conforming to the C89 standard, as the unsigned integer types have been specifically listed and therefore cannot be altered.

In future standards, this is not a guarantee and while you will not get undefined behaviour - you may lose data where unsigned long is smaller than size_t, meaning that you would display incorrect data to your user. In this situation I'd be hesitant to label it as "safe".


As an important additional note; this answer refers to compilers that are compliant with the C89 standard. It is possible for your C89 compiler to be "less than compliant" in the respects above, in which case - treat the behaviour to be similar to that of C99 or newer where you will not see undefined behaviour, but may suffer data loss if size_t is larger than unsigned long. To be clear though, this would not be complying with the C89 standard.

Beyond this, while my interpretation of the standard (1.7 Compliance) is that while it states extensions must not alter the behaviour of a "strictly conforming program" and as such cannot alter the fact that size_t must be unsigned long at largest without complying; it does not change the fact that such extensions do exist. For example GNU GCC does provide an extension that adds unsigned long long. In my view this is non-compliant, but the reality is you must be prepared to deal with such things and as such - while the standard says what you are doing is completely safe, you must be prepared for potential data loss where non-compliant compilers or extensions are used.


Please see here for previous discussion on this topic: https://stackoverflow.com/a/39441237/955340