web-dev-qa-db-fra.com

Scanf / Printf double variable C

Disons que j'ai le code suivant en C:

double var;
scanf("%lf", &var);
printf("%lf", var);
printf("%f", var);

Il lit la variable stdin 'var' puis s'imprime deux fois dans la sortie standard 'var'. Je comprends que vous lisiez une double variable de stdin, mais mes questions sont les suivantes:

  1. Pourquoi pouvez-vous imprimer un double avec% lf?
  2. Pourquoi pouvez-vous imprimer un double avec% f?
  3. Lequel est le meilleur et correct à utiliser?
32
Dragos Rizescu

Pour les fonctions à arguments variables telles que printf et scanf, les arguments sont promus; par exemple, tous les types entiers les plus petits sont promus à int, float est promu en double.

scanf prend les paramètres des pointeurs, ainsi la règle de promotion n'a aucun effet. Il doit utiliser %f pour float* et %lf pour double*.

printf ne verra jamais un argument float, float est toujours promu en tant que double. Le spécificateur de format est %f. Mais C99 dit aussi %lf est le même que %f dans printf:

C99 §7.19.6.1 La fonction fprintf

l (ell) Spécifie qu'une d, i, o, u, x ou X spécificateur de conversion s'applique à un long int ou unsigned long int argument; qu'un spécificateur de conversion n suivant s'applique à un pointeur sur un long int argument; qu'un spécificateur de conversion c suivant s'applique à un wint_t argument; qu'un spécificateur de conversion s suivant s'applique à un pointeur sur un wchar_t argument; ou n'a aucun effet sur les éléments suivants a, A, e, E, f , F, g ou G spécificateur de conversion.

38
Yu Hao

Quand un float est passé à printf, il est automatiquement converti en un double. Cela fait partie des promotions par défaut, qui s’appliquent aux fonctions ayant une liste de paramètres variables (contenant ...), principalement pour des raisons historiques. Par conséquent, le spécificateur "naturel" pour un float, %f, doit fonctionner avec un argument double. Alors le %f et %lf Les spécificateurs de printf sont identiques; ils prennent tous deux une valeur double.

Lorsque scanf est appelé, les pointeurs sont transmis et non les valeurs directes. Un pointeur sur float n'est pas converti en un pointeur sur double (cela pourrait ne pas fonctionner car l'objet pointé ne peut pas changer lorsque vous modifiez le type de pointeur). Donc, pour scanf, l'argument de %f doit être un pointeur sur float et l'argument de %lf doit être un pointeur sur double.

9
Eric Postpischil

Dans la mesure où je lis les pages du manuel, scanf indique que le modificateur de longueur indique (dans le cas de points flottants) que l'argument est de type double plutôt que de type float, vous pouvez donc avoir 'lf, le, lg'.

En ce qui concerne l’impression, officiellement, le manuel dit que "je" ne s’applique qu’aux types entiers. Il est donc possible que cela ne soit pas pris en charge sur certains systèmes ou par certaines normes. Par exemple, je reçois le message d'erreur suivant lors de la compilation avec gcc -Wall -Wextra -pedantic

a.c:6:1: warning: ISO C90 does not support the ‘%lf’ gnu_printf format [-Wformat=]

Donc, vous voudrez peut-être vérifier si votre standard supporte la syntaxe.

Pour conclure, je dirais que vous lisez avec '% lf' et que vous imprimez avec '% f'.

6
Artem Shinkarov