Question

En dehors de %hn et %hhn (où les spécifie h ou hh la taille du pointe à objet), quel est le point des modificateurs de h et hh pour spécificateurs format printf?

En raison de défaut des promotions qui sont requises par la norme à appliquer pour les fonctions variadique, il est impossible de passer des arguments de type char ou short (ou les variantes signé / non signé de celui-ci) à printf.

Selon 7.19.6.1 (7), le modificateur de h:

  

spéci fi es que d suivant, i, o, u, x, ou fi spécifique de conversion X er applique à un   short int ou argument int court non signé (l'argument   ont été promus en fonction des promotions entières, mais sa valeur doit   être converti en short int ou short int unsigned avant impression);   ou qu'une conversion n suivant spéci fi er s'applique à un pointeur sur un court   l'argument int.

Si l'argument était en fait de type short ou unsigned short, puis la promotion à int suivi d'un retour de conversion short ou unsigned short donnera les mêmes valeur promotion de int sans retour de conversion. Ainsi, pour les arguments de type short ou unsigned short, %d, %u, etc. devraient donner des résultats identiques à %hd, %hu, etc. (et de même pour les types de char et hh).

Pour autant que je sache, la seule situation où le modificateur de h ou hh pourrait être utile est lorsque l'argument a transmis une int en dehors de la gamme de short ou unsigned short, par exemple.

printf("%hu", 0x10000);

mais je crois comprendre que le passage du mauvais type comme cela se traduit par un comportement non défini de toute façon, de sorte que vous ne pouviez pas attendre d'imprimer 0.

Un cas du monde réel que j'ai vu est un code comme ceci:

char c = 0xf0;
printf("%hhx", c);

où l'auteur s'attend à imprimer f0 en dépit de la mise en œuvre ayant un type de char simple qui est signé (dans ce cas, printf("%x", c) imprimerait fffffff0 ou similaire). Mais cette attente justifiée?

(Note: Qu'est-ce qui se passe est que le type original était char, qui est promu int et à l'arrière converti en unsigned char au lieu de char, changeant ainsi la valeur qui est imprimé mais ne la norme précise ce comportement, ou est-ce. un détail de mise en œuvre que le logiciel peut être cassé compte sur?)

Autres conseils

En mode %...x, toutes les valeurs sont interprétées comme non signé. Les nombres négatifs sont donc imprimés que leurs conversions non signées. Dans le calcul du complément à 2, dont la plupart des processeurs utilisent, il n'y a aucune différence dans les motifs de bits entre un nombre négatif signé et son équivalent non signé positif, qui est définie par une arithmétique de module (en ajoutant la valeur maximale pour le domaine de plus un pour le numéro de négatif, selon à la norme C99). Beaucoup de Logiciel- en particulier le code de débogage les plus susceptibles d'utiliser les marques %x- l'hypothèse silencieuse que la représentation binaire d'une valeur négative signée et son qu'unsigned est le même, ce qui est vrai que sur une machine de complément à 2.

La mécanique de cette fonte sont telles que les représentations hexadécimaux de valeur impliquent toujours, peut-être à tort, qu'un certain nombre a été rendu en complément à 2, tant qu'il n'a pas atteint une condition de bord où les différentes représentations entières ont différentes gammes. Cela est vrai même pour les représentations arithmétiques où la valeur 0 n'est pas représentée avec le motif binaire de tous 0s.

Un short de négatif affiché comme unsigned long dans hexidecimal sera donc, sur toute machine, être rembourré avec f, en raison de l'extension de signe implicite dans la promotion, qui printf imprimera. valeur est le même, mais il est trompeur vraiment visuellement à la taille du champ, ce qui implique une quantité importante de gamme qui est tout simplement pas présente.

%hx tronque la représentation affichée pour éviter ce rembourrage, exactement comme vous concluez de votre cas d'utilisation dans le monde réel.

Le comportement de printf est indéfini lorsqu'il est passé un int en dehors de la gamme de short qui doit être imprimé comme short, mais la mise en œuvre de loin la plus facile simplement les rejets le bit par une brute baissés, et bien que la spécification ne < em> nécessitent tout comportement spécifique, à peu près toute mise en œuvre saine d'esprit va juste effectuer la troncature. Il sont des moyens généralement préférable de le faire, cependant.

Si printf est pas des valeurs de remplissage ou afficher des représentations non signées des valeurs signées, %h est pas très utile.

L'utilisation que je peux penser est pour le passage d'un unsigned short ou unsigned char et en utilisant les indicateurs de conversion de %x. Vous ne pouvez pas simplement utiliser un %x nu -. La valeur peut être promu int plutôt que unsigned int, et puis vous avez un comportement non défini

Vos alternatives sont soit explicitement jeter l'argument unsigned; ou à l'utilisation %hx / %hhx avec un argument nu.

Les arguments variadique à printf() et al sont automatiquement promus à l'aide des conversions par défaut, de sorte que toutes les valeurs de short ou char sont promus à int lorsqu'elle est transmise à la fonction.

En l'absence des modificateurs de h ou hh, vous devez masquer les valeurs transmises de manière fiable pour obtenir le comportement correct. Avec les modificateurs, vous n'avez plus à masquer les valeurs; la mise en œuvre de printf() fait le travail correctement.

Plus précisément, pour le format %hx, le code à l'intérieur printf() peut faire quelque chose comme:

va_list args;
va_start(args, format);

...

int i = va_arg(args, int);
unsigned short s = (unsigned short)i;
...print s correctly, as 4 hex digits maximum
...even on a machine with 64-bit `int`!

Je suppose que allègrement short est une quantité de 16 bits; la norme ne garantit pas en fait que, bien sûr.

Je l'ai trouvé utile pour éviter la coulée lors du formatage à caractères non signés hex:

        sprintf_s(tmpBuf, 3, "%2.2hhx", *(CEKey + i));

Il est une pratique de codage mineur, et a l'air plus propre que plusieurs moulages (OMI).

Je suis d'accord avec vous qu'il est pas strictement nécessaire, et donc, par cette raison est seul pas bon dans une fonction de bibliothèque C:)

Il est peut-être « gentil » pour la symétrie des différents drapeaux, mais il est le plus souvent contre-productive, car elle cache la règle « conversion int ».

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top