Spécificateur de format correct pour double dans printf


482

À quoi sert le spécificateur de format correct doubledans printf? Est-ce %fou est-ce %lf? Je le crois %f, mais je n'en suis pas sûr.

Exemple de code

#include <stdio.h>

int main()
{
   double d = 1.4;
   printf("%lf", d); // Is this wrong?
}

19
Si vous êtes coincé avec une bibliothèque C89, "%lf"n'est pas défini; dans les bibliothèques C99 et C11, il est défini comme étant identique à "%f".
pmg

1
Votre variante est aussi correcte que jamais. %lfest le spécificateur de format correct pour double. Mais c'est devenu ainsi en C99. Avant cela, il fallait utiliser %f.
AnT

Réponses:


626

"%f"est le (ou au moins un) format correct pour un double. Il n'y a pas de format pour a float, car si vous essayez de passer floatà printf, il sera promu doubleavant de le printfrecevoir 1 . "%lf"est également acceptable selon la norme actuelle - le lest spécifié comme n'ayant aucun effet s'il est suivi par le fspécificateur de conversion (entre autres).

Notez que c'est un endroit où les printfchaînes de format diffèrent considérablement des chaînes de format scanf(et fscanf, etc.). Pour la sortie, vous transmettez une valeur , qui sera promue de floatà doublelorsqu'elle est transmise en tant que paramètre variadic. Pour l'entrée, vous passez un pointeur , qui n'est pas promu, vous devez donc dire scanfsi vous voulez lire un floatou un double, donc pour scanf, cela %fsignifie que vous voulez lire un floatet %lfsignifie que vous voulez lire un double(et, pour ce que c'est vaut, pour un long double, vous utilisez %Lfpour printfou scanf).


1. C99, §6.5.2.2 / 6: "Si l'expression qui dénote la fonction appelée a un type qui n'inclut pas de prototype, les promotions entières sont effectuées sur chaque argument et les arguments de type float sont promus au double. Ce sont les promotions d'argument par défaut. " En C ++, le libellé est quelque peu différent (par exemple, il n'utilise pas le mot "prototype") mais l'effet est le même: tous les paramètres variadiques subissent des promotions par défaut avant d'être reçus par la fonction.


8
Notez que g++rejette %lflors de la compilation avec -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@kynan: Si c'est le cas (au moins en supposant une version actuelle de g ++), c'est un bogue dans g ++. Pour C89 / 90 et C ++ 98/03, l'autorisation létait une extension. Les normes C99 / 11 et C ++ 11 nécessitent l'implémentation pour le permettre.
Jerry Coffin

1
Chose curieuse, scanf ne fait défaut doublede représenté par %lf: il se plaint que prévu float *et a trouvé double *avec juste %f.
Eric Dand

1
@JerryCoffin g ++ utilise toujours le mode g ++ 98 par défaut
MM

5
@EricDand C'est parce que scanfprend des pointeurs vers où stocker ce qu'il lit, a donc besoin de savoir quelle est la taille de l'espace visé , tandis que printfprend les valeurs elles-mêmes, et "promotions d'argument par défaut" signifient que les deux finissent par doubles, donc le lest essentiellement facultatif.
TripeHound

63

Compte tenu de la norme C99 (à savoir le projet N1256 ), les règles dépendent du type de fonction: fprintf (printf, sprintf, ...) ou scanf.

Voici les parties pertinentes extraites:

Préface

Cette deuxième édition annule et remplace la première édition, ISO / IEC 9899: 1990, telle que modifiée et corrigée par ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995 et ISO / IEC 9899 / COR2: 1996. Les principaux changements par rapport à l'édition précédente incluent:

  • %lf spécificateur de conversion autorisé dans printf

7.19.6.1 La fprintffonction

7 Les modificateurs de longueur et leurs significations sont:

l (ell) Spécifie que (...) n'a aucun effet sur un spécificateur de conversion a, A, e, E, f, F, g ou G suivant.

L Spécifie qu'un spécificateur de conversion a, A, e, E, f, F, g ou G suivant s'applique à un argument long double.

Les mêmes règles spécifiées pour fprintfappliquer pour printf, sprintfet des fonctions similaires.

7.19.6.2 La fscanffonction

11 Les modificateurs de longueur et leurs significations sont:

l (ell) Spécifie que (...) qu'un spécificateur de conversion a, A, e, E, f, F, g ou G suivant s'applique à un argument dont le pointeur de type est double;

L Spécifie qu'un spécificateur de conversion a, A, e, E, f, F, g ou G suivant s'applique à un argument avec un pointeur de type sur double long.

12 Les spécificateurs de conversion et leurs significations sont: a, e, f, g Correspond à un nombre à virgule flottante éventuellement signé, (...)

14 Les spécificateurs de conversion A, E, F, G et X sont également valides et se comportent de la même manière que respectivement a, e, f, g et x.

La longue histoire courte, pour fprintfles spécificateurs suivants et les types correspondants sont spécifiés:

  • %f -> double
  • %Lf -> long double.

et fscanfc'est:

  • %f -> flotter
  • %lf -> double
  • %Lf -> long double.

25

Cela peut être %f, %gou %eselon la façon dont vous souhaitez que le nombre soit formaté. Voir ici pour plus de détails. Le lmodificateur est requis dans scanfavec double, mais pas dans printf.


1
-1: le lmodificateur (en minuscules) concerne les types entiers ( cplusplus.com/reference/clibrary/cstdio/printf ) et les Ltypes à virgule flottante. De plus, le Lmodificateur attend un long double, pas un simple double.
user470379

10
user470379: Où est donc la contradiction avec ma réponse? N'ai-je pas dit que ce ln'est pas nécessaire printfpour double.
vitaut

16

Le format %lfest un printfformat parfaitement correct pour double, exactement comme vous l'avez utilisé. Il n'y a rien de mal avec votre code.

Le format %lfin printfn'était pas pris en charge dans les anciennes versions (antérieures à C99) du langage C, ce qui créait une "incohérence" superficielle entre les spécificateurs de format pour doublein printfet scanf. Cette incohérence superficielle a été corrigée dans C99.

Vous n'êtes pas obligé d'utiliser %lfavec doublein printf. Vous pouvez également l'utiliser %f, si vous préférez ( %lfet %fsont équivalents en printf). Mais dans le C moderne, il est parfaitement logique de préférer utiliser %favec float, %lfavec doubleet %Lfavec long double, de manière cohérente dans printfet scanf.


Avec scanf(), "%f", "%lf"correspondre à une float *, double *, et non float, doublecomme le laisse entendre la dernière ligne.
chux

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.