How to use printf to display off_t, nlink_t, size_t and other special types?

18,378

There isn't a fully portable way to do it, and it is a nuisance.

C99 provides a mechanism for built-in types like size_t with the %zu notation (and there are some extra, similar qualifiers).

It also provides the <inttypes.h> header with macros such as PRIX32 to define the correct qualifier for printing a 32-bit hexadecimal constant (in this case):

printf("32-bit integer: 0x%08" PRIX32 "\n", var_of_type_int32_t);

For the system-defined types (such as those defined by POSIX), AFAIK, there is no good way to handle them. So, what I do is take a flying guess at a 'safe' conversion and then print accordingly, including the cast, which is what you illustrate in the question. It is frustrating, but there is no better way that I know of. In case of doubt, and using C99, then conversion to 'unsigned long long' is pretty good; there could be a case for using a cast to uintmax_t and PRIXMAX or equivalent.

Or, as FUZxxl reminded me, you can use the modifier j to indicate a 'max' integer type. For example:

printf("Maximal integer: 0x%08jX\n", (uintmax_t)var_of_type_without_format_letter);
Share:
18,378
Kasper
Author by

Kasper

PhD student at the Institute for Theoretical Physics at KU Leuven

Updated on June 08, 2022

Comments

  • Kasper
    Kasper almost 2 years

    In my program, I stat the files they want and send the data over. The fields of a stat struct are all special types:

    struct stat {
      dev_t     st_dev;     /* ID of device containing file */
      ino_t     st_ino;     /* inode number */
      mode_t    st_mode;    /* protection */
      nlink_t   st_nlink;   /* number of hard links */
      uid_t     st_uid;     /* user ID of owner */
      gid_t     st_gid;     /* group ID of owner */
      dev_t     st_rdev;    /* device ID (if special file) */
      off_t     st_size;    /* total size, in bytes */
      blksize_t st_blksize; /* blocksize for file system I/O */
      blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
      time_t    st_atime;   /* time of last access */
      time_t    st_mtime;   /* time of last modification */
      time_t    st_ctime;   /* time of last status change */
    };
    

    The relevant code for my question follows:

    len = snprintf( statbuf, STAT_BUFFER_SIZE,
      "%crwxrwxrwx %lu %u %u %lld %s %s\r\n",
      S_ISDIR( filestats.st_mode ) ? 'd' : '-',
      (unsigned long ) filestats.st_nlink,
      filestats.st_uid,
      filestats.st_gid,
      (unsigned long long ) filestats.st_size,
      date,
      filename);
    

    How do I print these types in a portable and efficient way? At first I did it without casts by guessing the correct format specifiers. Apart from being an annoying programming habit, this also meant my code wouldn't work on a 32 bit system. Now with the casts it seems to work, but on how many platforms?