Comment utiliser printf pour afficher off_t, nlink_t, size_t et d'autres types spéciaux?
-
05-07-2019 - |
Question
Dans mon programme, je récupère les fichiers qu’ils veulent et les envoie. Les champs d'une stat struct
sont tous des types spéciaux:
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 */
};
Le code correspondant à ma question est le suivant:
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);
Comment puis-je imprimer ces types de manière portable et efficace? Au début, je l'ai fait sans lancer en devinant les spécificateurs de format corrects. En plus d'être une habitude de programmation agaçante, cela signifiait également que mon code ne fonctionnerait pas sur un système 32 bits. Maintenant, avec les acteurs, cela semble fonctionner, mais sur combien de plates-formes?
La solution
Il n’existe pas de méthode totalement portable pour le faire et c’est une nuisance.
C99 fournit un mécanisme pour les types intégrés tels que size_t
avec la notation %zu
(et il existe quelques qualificateurs supplémentaires similaires).
Il fournit également à l'en-tête <inttypes.h>
des macros telles que PRIX32 pour définir le qualificatif approprié pour l'impression d'une constante hexadécimale 32 bits (dans ce cas):
printf("32-bit integer: 0x%08" PRIX32 "\n", var_of_type_int32_t);
Pour les types définis par le système (tels que ceux définis par POSIX), autant que je sache, il n'y a pas de bon moyen de les gérer. Donc, ce que je fais est de tenter une conversion "en toute sécurité" puis d’imprimer en conséquence, y compris le casting, ce que vous illustrez dans la question. C'est frustrant, mais il n'y a pas de meilleure façon que je sache. En cas de doute, et en utilisant C99, la conversion en 'unsigned long long' est plutôt bonne; il pourrait y avoir un cas pour utiliser un cast sur uintmax_t
et PRIXMAX ou équivalent.
Ou, comme FUZxxl m'a rappelé , vous pouvez utiliser le modificateur j
pour indiquer un type entier 'max'. Par exemple:
printf("Maximal integer: 0x%08jX\n", (uintmax_t)var_of_type_without_format_letter);