Comment utiliser printf pour afficher off t, nlink t, taille t et d'autres types spéciaux?

Dans mon programme, je stat les fichiers qu'ils veulent et envoie les données. 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 pertinent pour ma question suit:

len = snprintf( statbuf, STAT_BUFFER_SIZE,
  "%crwxrwxrwx %lu %u %u %lld %s %srn",
  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 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 ennuyeuse, cela signifiait également que mon code ne fonctionnerait pas sur un système 32 bits. Maintenant, avec les moulages, il semble fonctionner, mais sur combien les plates-formes?

26

1 réponses

Il n'y a pas de moyen entièrement portable de le faire, et c'est une nuisance.

C99 fournit un mécanisme pour les types intégrés comme size_t avec la notation %zu (et il y a quelques qualificatifs supplémentaires similaires).

Il fournit également l'en-tête <inttypes.h> avec des macros telles que PRIX32 pour définir le qualificatif correct 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), AFAIK, il n'y a pas de bon moyen de les gérer. Donc, ce que je fais est de deviner une conversion "sûre", 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 meilleur moyen que je connaisse. En cas de doute, et en utilisant C99, alors la conversion en 'unsigned long long' est assez bonne; il pourrait y avoir un cas pour utiliser un cast à uintmax_t et PRIXMAX ou équivalent.

, Ou, comme FUZxxl rappelé moi, vous pouvez utiliser le modificateur j pour indiquer un "max" type entier. Par exemple:

printf("Maximal integer: 0x%08jX\n", (uintmax_t)var_of_type_without_format_letter);
25
répondu Jonathan Leffler 2017-05-23 10:33:58