How to use printf to display off_t, nlink_t, size_t and other special types?
c, linux, portability, printf
Solution
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);
Problem
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?