Pourquoi scanf () a-t-il besoin de «% lf» pour les doubles, alors que printf () est d'accord avec seulement «% f»?

179

Pourquoi a-t-il scanf()besoin du lin " %lf" lors de la lecture de a double, quand printf()peut utiliser " %f" indépendamment du fait que son argument soit a doubleou a float?

Exemple de code:

double d;
scanf("%lf", &d);
printf("%f", d);
Raldi
la source
1
Je ne comprends pas ce que vous entendez par POINTER ici. Dans scanf, nous ne passons que l'adresse & variable (ie), donc où est le pointeur
7
@deetchanya En C, lorsque vous "prenez l'adresse" d'une variable avec l' &opérateur unaire , le résultat de cette opération est un pointeur vers l'emplacement de stockage de la variable en mémoire. C'est ce pointeur qui est passé à scanf.
zwol
ceci est un autre article concernant ce stackoverflow.com/questions/9291348/…
vimalpt

Réponses:

207

Parce que C promouvra les flottants en doubles pour les fonctions qui acceptent des arguments variables. Les pointeurs ne sont pas promus vers quoi que ce soit, vous devriez donc utiliser %lf, %lgou %le(ou %laen C99) pour lire en double.

MSN
la source
26

Depuis С99, la correspondance entre les spécificateurs de format et les types d'arguments à virgule flottante en C est cohérente entre printfet scanf. C'est

  • %f pour float
  • %lf pour double
  • %Lf pour long double

Il se trouve que lorsque des arguments de type floatsont passés en tant que paramètres variadiques, ces arguments sont implicitement convertis en type double. C'est la raison pour laquelle dans les printfspécificateurs de format %fet %lfsont équivalents et interchangeables. Dans printfvous pouvez "utiliser de manière croisée" %lfavec floatou %favec double.

Mais il n'y a aucune raison de le faire dans la pratique. N'utilisez pas %fd' printfarguments de type double. C'est une habitude répandue qui est née à C89 / 90 fois, mais c'est une mauvaise habitude. Utilisation %lfen printfpour doubleet garder %fréservé aux floatarguments.

Fourmi
la source
1
Je dirais que l'utilisation %fde printf est une bonne habitude car votre code fonctionne toujours, alors que l'utilisation %lfpeut échouer si le compilateur n'a pas de bibliothèque compatible C99. Malheureusement, cette situation se produit dans la réalité.
MM
Depuis С99, la correspondance entre les spécificateurs de format et les types d'arguments à virgule flottante en C est cohérente entre printfet scanf. Notez que cela n'implique pas que l'utilisation du même spécificateur de format signifie que les données écrites par a [f]printf()peuvent être lues par [f]scanf(). En général, en utilisant le même spécificateur de format pour scanf()qui a été utilisé par printf()ne pas lire les données avec succès. Par exemple, l' espace de remplissage qui peut être inséré par un prinf()de » "%d"spécificateur de format sera ignorée par ce même "%d"spécificateur de format dans un scanf()appel.
Andrew Henle
16

scanfa besoin de connaître la taille des données pointées par &dpour les remplir correctement, alors que les fonctions variadiques promeuvent les flottants en doubles ( printfje ne sais pas vraiment pourquoi), donc obtient toujours un double.

Tanktalus
la source
1
Une fonction variadique est très fragile, car elle doit être capable de connaître le type et la taille exacts de tous les paramètres qui lui sont passés, et elle ne peut pas appliquer cela au moment de la compilation. Si une variable est du mauvais type, la mauvaise valeur sera lue; si c'est la mauvaise taille, toutes les variables suivantes seront également mal lues. Si deux tailles différentes de flotteur pouvaient être adoptées, cela causerait toutes sortes de problèmes désagréables et faciles à manquer.
mwfearnley
7

Parce que sinon, scanf pensera que vous passez un pointeur vers un flottant qui est d'une taille plus petite qu'un double, et il renverra une valeur incorrecte.

Jim Buck
la source
2

L'utilisation d'un flottant ou d'une valeur double dans une expression C entraînera une valeur double de toute façon, donc printf ne peut pas faire la différence. Alors qu'un pointeur vers un double doit être explicitement signalé à scanf comme distinct d'un pointeur à float, car ce que le pointeur pointe est ce qui compte.

fcw
la source
5
float est converti en double dans ce cas car les arguments font partie d'une liste d'arguments de longueur variable, les float ne sont pas toujours convertis en doubles en C.
Robert Gamble
1
Dans les versions pré-standard du langage C, les floatvaleurs étaient automatiquement promues doubledans les expressions. Cette règle a été abandonnée dans la norme C. En général, elle floatn'est pas promue doubledans les expressions. Il n'est promu que doublelorsqu'il est passé en tant qu'argument variadique, ce qui se passe dans ce cas.
Du