Comment convertir de manière portable une chaîne en un type entier peu commun?

Un peu d’arrière-plan: si je voulais utiliser, par exemple, scanf() pour convertir une chaîne en un type entier standard, comme uint16_t , j’utiliserais SCNu16 partir de , comme ceci:

 #include  #include  uint16_t x; char *xs = "17"; sscanf(xs, "%" SCNu16, &x); 

Mais un type entier plus rare, comme pid_t n’a pas une telle chose; seuls les types entiers normaux sont supportés par . Pour convertir l’inverse, en printport printf() un pid_t , je peux le intmax_t en intmax_t et utiliser PRIdMAX , comme ceci:

 #include  #include  #include  pid_t x = 17; printf("%" PRIdMAX, (intmax_t)x); 

Cependant, il ne semble pas y avoir de moyen de transférer scanf() dans un pid_t . Voici donc ma question: comment faire cela de manière portable?

 #include  #include  pid_t x; char *xs = 17; sscanf(xs, "%u", &x); /* Not portable! pid_t might not be int! /* 

J’ai pensé à scanf() dans un intmax_t , puis en vérifiant que la valeur est dans les limites de pid_t avant de lancer pid_t , mais il ne semble pas y avoir de moyen d’obtenir les valeurs maximales ou minimales de pid_t .

Il existe une solution robuste et portable, qui consiste à utiliser strtoimax() et à vérifier les débordements.

En d’autres intmax_t , intmax_t un intmax_t , intmax_t recherche une erreur dans strtoimax() , puis je vérifie également s’il “tient” dans un pid_t en le lançant et en le comparant à la valeur initiale intmax_t .

 #include  #include  #include  #include  char *xs = "17"; /* The ssortingng to convert */ intmax_t xmax; char *tmp; pid_t x; /* Target variable */ errno = 0; xmax = strtoimax(xs, &tmp, 10); if(errno != 0 or tmp == xs or *tmp != '\0' or xmax != (pid_t)xmax){ fprintf(stderr, "Bad PID!\n"); } else { x = (pid_t)xmax; ... } 

Il n’est pas possible d’utiliser scanf() , car, comme je l’ai dit dans un commentaire, scanf() ne détectera pas les débordements . Mais j’avais tort de dire qu’aucune des fonctions strtoll() ne prend un intmax_t ; strtoimax() fait!

Il ne fonctionnera pas non plus d’utiliser strtoimax() moins de connaître la taille de votre type entier ( pid_t , dans ce cas).

Cela dépend de la façon dont vous voulez être portable. POSIX dit que pid_t est un type entier signé utilisé pour stocker les ID de processus et les ID de groupes de processus. En pratique, vous pouvez supposer que la sécurité est suffisamment long . A défaut, votre intmax_t doit être suffisamment grand (il acceptera donc tout pid_t valide); Le problème est que ce type pourrait accepter des valeurs qui ne sont pas légitimes dans pid_t . Vous êtes coincé entre le marteau et l’enclume.

J’utiliserais long et ne m’inquiéterais pas beaucoup à ce sujet, sauf pour un commentaire obscur quelque part qu’un archéologue logiciel de 100 ans va trouver et observer donne une raison pour laquelle le processeur 256 bits s’arrête de fonctionner lorsqu’il reçoit une valeur de 512 bits comme un pid_t .

POSIX 1003.1-2008 est maintenant disponible sur le Web (les 3872 pages, en PDF et HTML). Vous devez vous inscrire (gratuit). J’y suis arrivé de la librairie du groupe ouvert .

Tout ce que je vois, c’est qu’il doit s’agir d’un type entier signé. Il est clair que toutes les valeurs d’entiers signés valides entrent dans intmax_t . Je ne trouve aucune information dans ou qui indique PID_T_MAX ou PID_T_MIN ou toute autre valeur de ce type (mais je ne l’ai que ce soir-là, elle peut être masquée l’a cherché). OTOH, je maintiens mon commentaire initial – je pense que les valeurs 32 bits sont adéquates d’un sharepoint vue pragmatique, et j’utiliserais quand même long , ce qui serait 64 bits sur des machines 8 bits. Je suppose que la pire chose qui puisse arriver est qu’un processus “avec les privilèges appropriés” lise une valeur trop grande et envoie un signal au mauvais processus en raison d’une incompatibilité de types. Je ne suis pas convaincu que cela m’inquiète.

… oooh! … p400 sous

L’implémentation doit prendre en charge un ou plusieurs environnements de programmation dans lesquels les largeurs de blksize_t, pid_t, size_t, ssize_t et suseconds_t ne sont pas supérieures à la largeur du type long.

Si vous êtes vraiment inquiet, vous pouvez _assert(sizeof(pid_t) <= long) ou le type de votre choix pour votre commande '%'.

Comme expliqué dans cette réponse , la spécification dit signed int . Si 'int' change, votre '% u' change par définition avec lui.