Why are variables of type size_t casted to (unsigned) in a printf call?

Viewed 66

I was writing a program and looking up strlen() function on this website http://www.cplusplus.com/reference/cstring/strlen/. I saw that in the example where the function was used, the author of the code put (unsigned) to cast the result of the function to unsigned. I understand that it is done so because the function returns size_t type, which is unsigned, but is this really necessary?

/* strlen example */
#include <stdio.h>
#include <string.h>

int main ()
{
  char szInput[256];
  printf ("Enter a sentence: ");
  gets (szInput);
  printf ("The sentence entered is %u characters long.\n",(unsigned)strlen(szInput));
  return 0;
}
2 Answers

In the code example this is because it is the argument corresponding to a %u format specifier in printf.

The variadic arguments for printf must have exactly the correct type for the specifier, otherwise the behaviour is undefined. The argument type for %u is unsigned.

size_t is a typedef that may or may not resolve to unsigned, so the cast is necessary for the call to be well-defined on all platforms.

Another approach would be to use the %zu format specifier which is designed for size_t, although that has a practical issue that it will fail if the library is not C99-compliant.

This is done for portability. There is a modifier for size_t format descriptors, using the letter z, as in %zu (meaning unsigned format for size_t operand) that will make to accept a size_t argument, independent of the architecture you are using.

Depending on the flavour of unix you use, of the standard you follow, you'll encounter systems in which z is accepted or not, in which size_t exists or not (very old systems had no size_t type) so, as the result of strlen() is probably known to the author of the code to be short, then the most portable solution is to convert the data to a type that is allowed by printf() and then use a known format specifier. In your case the author decided to use (unsigned) as probably the program has changed from 32bit architectures (with or without the z modifier) to 64bit one, without the knowledge of if it needs an unsigned int or an unsigned long to specify the result. As the string is short enough to fit in an unsigned, there's no need to use the z modifier, which probably is either not known to the user, or not present in the compiler implementation used by her/him.

This is quite common as one letter should be reserved in systems for off_t, dev_t, ino_t, etc. Many of them operating system dependant, and not included in the standard the user is normally programming.

Related