2009-07-26 3 views
16

Tout en recherchant comment faire multi-plateforme printf() chaînes de format en C (c'est-à-dire, en tenant compte du nombre de bits que je suppose que chaque argument entier à printf() devrait être) j'ai couru this section of the Wikipedia article on printf(). L'article traite des options non standard qui peuvent être transmis à printf() chaînes de format, tels que (ce qui semble être une extension spécifique à Microsoft):Pourquoi les nouvelles options de format printf() n'étaient-elles pas nouvelles (en fonction de la largeur de bit) adoptées dans le cadre de C99?

printf("%I32d\n", my32bitInt); 

Il poursuit en disant que:

ISO C99 inclut le fichier inttypes.h en-tête qui inclut un certain nombre de macros à utiliser dans le codage printf indépendant de la plate-forme.

... puis d'énumérer un ensemble de macros qui peuvent être trouvées dans ledit en-tête. En regardant le fichier d'en-tête, pour les utiliser je devrais écrire:

printf("%"PRId32"\n", my32bitInt); 

Ma question est: ai-je raté quelque chose? Est-ce vraiment la façon standard de le faire? Si oui, pourquoi? (Bien que je ne sois pas surpris que je n'ai jamais vu de code qui utilise les chaînes de format de cette façon, car il semble si lourd ...)

Répondre

16

Justification C semble impliquer que <inttypes.h> normalise la pratique actuelle:

<inttypes.h> a été dérivé de l'en-tête du même nom se trouve sur plusieurs existant 64 bits systèmes.

mais le reste du texte n'écrit pas à propos de ces macros, et je ne me souviens pas qu'elles existaient à ce moment-là. Ce qui suit est juste de la spéculation, mais éduqué par l'expérience du fonctionnement des comités de standardisation.

Un avantage des macros C99 sur la standardisation spécificateur de format supplémentaire pour printf (notez que C99 a également fait ajouter un peu) est que la fourniture <inttypes.h> et <stdint.h> lorsque vous avez déjà une implémentation supportant les fonctionnalités nécessaires à une mise en œuvre de manière spécifique est simplement en train d'écrire deux fichiers avec typedef et macros adéquats. Cela réduit le coût de conformité de l'implémentation existante, réduit le risque de casser les programmes existants qui utilisent les fonctionnalités spécifiques de l'implémentation existantes (la méthode standard n'interfère pas) et facilite le portage de programmes conformes à la mise en œuvre qui ne disposent pas en-têtes (ils peuvent être fournis par le programme). De plus, si les modalités d'implémentation spécifiques variaient déjà à ce moment, cela ne favorise pas une mise en œuvre par rapport à une autre.

+0

Un inconvénient: appeler C de l'assemblage. –

8

Correct, c'est ainsi que la norme C99 dit que vous devriez les utiliser. Si vous voulez vraiment un code portablt qui est 100% conforme aux normes de la lettre, vous devez toujours imprimer un int en utilisant "%d" et un int32_t en utilisant "%"PRId32.

La plupart des gens ne s'en soucieront pas, car il y a très peu de cas où cela ne serait pas important. Sauf si vous transférez votre code à Win16 ou DOS, vous pouvez supposer que sizeof(int32_t) <= sizeof(int), donc il est inoffensif d'imprimer accidentellement un int32_t comme int. De même, un long long est quasiment universellement 64 bits (bien que cela ne soit pas garanti), donc l'impression d'un int64_t en tant que long long (par exemple avec un spécificateur %llx) est également sûre.

Les types int_fast32_t, int_least32_t et autres ne sont pratiquement jamais utilisés, vous pouvez donc imaginer que leurs spécificateurs de format correspondants sont encore plus rarement utilisés.

+0

"Ma question est: est-ce que je manque quelque chose? Est-ce vraiment la façon standard de le faire?" Si oui, pourquoi? ** " –

+0

Bien que j'aimerais vraiment connaître le" pourquoi ", je réalise qu'il s'agit en quelque sorte d'une question rhétorique. Je doute que quiconque le sache, à moins d'assister à la discussion au sein des organismes de normalisation au sujet de C99. Je suis en train d'imaginer un groupe d'ingénieurs qui discutent des mérites d'une modification de printf() alors qu'ils avaient déjà des chaînes de format pour imprimer n'importe quoi. Ils ont probablement décidé d'en faire un #define et d'en finir avec ça. Donc, à moins que quelqu'un d'autre ait un aperçu profond ici, j'accepterai probablement cette réponse; cela répond à la plupart de mes questions. – mpontillo

+1

Peut-être que j'écris trop de code embarqué, mais je suis un grand fan de l'utilisation des macros 'PRIx ##' dans mes chaînes printf. Je suppose seulement que 'int' est 16 bits ou plus. Une fois que vous l'avez fait, vous vous y habituerez. – tomlogic

1

Je ne peux que spéculer sur pourquoi. J'aime la réponse de AProgrammer ci-dessus, mais il y a un aspect négligé: qu'allez-vous ajouter à printf comme modificateur de format? Il existe déjà deux manières différentes d'utiliser des nombres dans une chaîne au format printf (largeur et précision). Ajouter un troisième type de nombre pour dire combien de bits de précision sont dans l'argument serait bien, mais où allez-vous le mettre sans confondre les gens? Malheureusement, l'un des défauts de C est que printf n'a pas été conçu pour être extensible.

Les macros sont terribles, mais lorsque vous devez écrire du code portable sur des plates-formes 32 bits et 64 bits, elles sont une bénédiction. Certainement sauvé mon bacon.

Je pense que la réponse à votre question pourquoi est soit

  • Personne ne pouvait penser à une meilleure façon de le faire, ou
  • Le comité des normes ne pouvaient se mettre d'accord sur tout ce qu'ils estimaient être clairement meilleur.
+0

Bon point, mais Microsoft a ajouté un moyen de le faire en utilisant un modificateur de format (ce qui est moche, mais cela fonctionne). Une façon de procéder aurait pu être de découpler la pensée actuelle «d = int, u = unsigned int» et de réaffecter les spécificateurs de type tels que «d = int32_t, u = uint32_t». Cela aurait pu être moins perturbant pour C que la route Java. (spécifiez la largeur de bit de chaque type explicitement - ce qu'ils auraient peut-être dû faire au début ...) Mais cela aurait quand même exigé des changements dans les implémentations de printf(). Je pense qu'ils ont juste pris la facilité. – mpontillo

+0

@Mike: avez-vous un pointeur vers Microsoft? Je déteste les macros. Et j'ai déjà une grande partie de l'implémentation de printf. –

+0

Il a été mentionné sur l'article Wikipedia que j'ai lié, mais ici il est directement à partir de la source: http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx – mpontillo

1

Autre possibilité: rétrocompatibilité. Si vous ajoutez d'autres spécificateurs de format à printf ou des options supplémentaires, il est possible qu'un spécificateur dans un code pré-C99 ait une chaîne de format interprétée différemment.

Avec la modification C99, vous ne modifiez pas la fonctionnalité de printf.

2

Vous pouvez toujours convertir vers le haut et utiliser %jd qui est le spécificateur de format intmax_t.

printf("%jd\n", (intmax_t)(-2)); 

J'utilisé intmax_t pour montrer que toute intXX_t peut être utilisé, mais simplement coulée à long est beaucoup mieux pour le int32_t cas, utilisez %ld.

+0

+1 pour l'idée intéressante, mais je ne suis pas sûr que j'aime l'idée de potentiellement couler un entier de 32 bits à une valeur de 64 bits + sur un système embarqué ... se sent juste mal en quelque sorte. ;-) – mpontillo

+0

Lorsque vous utilisez 'printf', perdre 4 octets pour le stockage temporaire (le cas échéant) est le moindre de vos problèmes de performance! ;) – lambdapower

Questions connexes