Dlaczego scanf () potrzebuje podwójnego „% lf”, skoro printf () jest w porządku z „% f”?

179

Dlaczego scanf()potrzebuje l%lf” podczas czytania double, kiedy printf()może używać „ %f” bez względu na to, czy jego argumentem jest doublea float?

Przykładowy kod:

double d;
scanf("%lf", &d);
printf("%f", d);
raldi
źródło
1
Nie rozumiem, co masz na myśli tutaj POINTER. W scanf przekazujemy tylko adres i zmienną (tj.) Adres, więc gdzie jest wskaźnik
7
@deetchanya W C, gdy „pobierasz adres” zmiennej &operatorem jednoargumentowym , wynikiem tej operacji jest wskaźnik do miejsca przechowywania zmiennej w pamięci. Jest to wskaźnik, który jest przekazywany scanf.
zwolnienie
jest to kolejny post dotyczący tego stackoverflow.com/questions/9291348/…
vimalpt

Odpowiedzi:

207

Ponieważ C będzie promować zmiennoprzecinkowe do podwójnych dla funkcji, które przyjmują zmienne argumenty. Wskaźniki nie są promowane do niczego, więc powinieneś być w użyciu %lf, %lgczy %le(lub %law C99), aby czytać w deblu.

MSN
źródło
26

Od czasu С99 dopasowanie specyfikatorów formatu do typów argumentów zmiennoprzecinkowych w C jest spójne między printfi scanf. To jest

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

Zdarza się tak, że gdy argumenty typu floatsą przekazywane jako parametry variadic, takie argumenty są domyślnie konwertowane na typ double. To jest powód, dlaczego w printfformacie specyfikatorami %fi %lfsą równoważne i wymienne. W printf„cross-use” %lfz floatlub %fz double.

Ale nie ma powodu, aby robić to w praktyce. Nie stosować %fdo printfargumentów typu double. Jest to powszechny nawyk urodzony w C89 / 90 razy, ale jest to zły nawyk. Zastosowanie %lfw printfza doublei ciągle %fzarezerwowane dla floatargumentów.

Mrówka
źródło
1
Powiedziałbym, że używanie %fw printf jest dobrym nawykiem, ponieważ wtedy twój kod zawsze działa, podczas gdy używanie %lfmoże się nie powieść, jeśli kompilator nie ma biblioteki zgodnej z C99. Niestety taka sytuacja zdarza się w rzeczywistości.
MM
Od czasu С99 dopasowanie specyfikatorów formatu do typów argumentów zmiennoprzecinkowych w C jest spójne między printfi scanf. Zauważ, że nie oznacza to, że użycie tego samego specyfikatora formatu oznacza, że ​​dane zapisane przez a [f]printf()mogą być odczytane przez [f]scanf(). Ogólnie rzecz biorąc, użycie tego samego specyfikatora formatu, scanf()który był używany przez printf(), nie spowoduje pomyślnego odczytania danych. Na przykład, przestrzeń wyściółka, która może być włożona przez prinf()„s "%d"formatu specyfikatora zostaną pominięte przez tego samego "%d"formatu specyfikatora w scanf()rozmowy.
Andrew Henle
16

scanfmusi znać rozmiar danych wskazywanych przez, &daby je poprawnie wypełnić, podczas gdy funkcje variadic promują zmienne do podwójnych (nie do końca pewni dlaczego), więc printfzawsze dostaje double.

Tanktalus
źródło
1
Funkcja variadic jest bardzo delikatna, ponieważ musi znać dokładny typ i rozmiar wszystkich przekazywanych jej parametrów i nie może tego wymusić w czasie kompilacji. Jeśli zmienna jest niewłaściwego typu, odczytana zostanie niewłaściwa wartość; jeśli ma niewłaściwy rozmiar, wszystkie zmienne po nim również zostaną źle odczytane. Gdyby można było podać dwa różne rozmiary pływaka, spowodowałoby to wszelkiego rodzaju nieprzyjemne i łatwe do przeoczenia problemy.
mwfearnley,
7

Ponieważ inaczej scanf pomyśli, że przekazujesz wskaźnik do liczby zmiennoprzecinkowej, która jest mniejsza niż podwójna, i zwróci niepoprawną wartość.

Jim Buck
źródło
2

Użycie wartości zmiennoprzecinkowych lub podwójnych w wyrażeniu C spowoduje, że i tak będzie to wartość podwójna, więc printf nie może odróżnić różnicy. Podczas gdy wskaźnik do podwójnej liczby musi być wyraźnie zasygnalizowany, aby skanować jako odrębny od wskaźnika do liczby zmiennoprzecinkowej, ponieważ liczy się to, na co wskazuje wskaźnik.

fcw
źródło
5
Pływak jest konwertowany do podwójnej w tym przypadku , ponieważ argumenty są częścią listy argumentów o zmiennej długości, pływaki nie są zawsze konwertowane do podwójnej w C
Robert Gamble
1
W standardowych wersjach C floatwartości języka były automatycznie promowane doublew wyrażeniach. Ta zasada została porzucona w standardzie C. Zasadniczo floatnie jest promowana doublew wyrażeniach. Awansuje się tylko doublewtedy, gdy zostanie przekazany jako argument variadic, co dzieje się w tym przypadku.
AnT