2008-10-16 5 views
162

Dlaczego jest tak, że scanf() potrzebuje l w „%lf” podczas czytania double, gdy printf() można użyć „%f”, niezależnie od tego, czy jego argument jest double lub float?Dlaczego scanf() potrzebuje "% lf" dla podwójnych, gdy printf() jest w porządku z "% f"?

Przykładowy kod:

double d; 
scanf("%lf", &d); 
printf("%f", d); 
+1

Nie rozumiem, co masz na myśli przez POINTER tutaj. W scanf podajemy tylko adres zmienny (tj.), Więc gdzie znajduje się wskaźnik –

+7

@deetchanya In C, kiedy "przyjmiemy adres" zmiennej z operatorem jednoargumentowym '&', wynikiem tej operacji jest wskaźnik do miejsce przechowywania zmiennej w pamięci. Jest to wskaźnik, który jest przekazywany do 'scanf'. – zwol

+0

to kolejny wpis dotyczący tego https: // stackoverflow.com/questions/9291348/why-is-scanf-not-working-as-expected-when-writing-to-a-string-literal – vimalpt

Odpowiedz

192

Ponieważ C będzie promować płynie do podwaja dla funkcji, które mają zmienne argumentów. Wskaźniki nie są promowane do niczego, więc powinieneś używać %lf, %lg lub %le (lub %la w C99) do czytania w deblu.

+3

Domyślne promocje są standardowymi C, a nie tylko MSVC. –

+0

Naprawiono zgodnie z twoim komentarzem. YAY! – MSN

+4

+1 za bycie dokładnie w porządku. IMHO, pokazuje, że scanf() jest ohydną funkcją, którą powinieneś tolerować tylko wtedy, gdy nie ma alternatywy. Zbyt łatwe jest wprowadzanie podstępnych defektów przez przekazywanie wskaźników do niewłaściwych danych i oczywiście nie ma sprawdzania parametrów przekazywanych do nich parametrów. – AAT

16

scanf musi znać rozmiar danych jest skierowany na przez &d aby wypełnić go prawidłowo, natomiast funkcje zmiennej liczbie argumentów promować płynie do deblu (nie do końca wiem, dlaczego), więc printf jest zawsze uzyskanie double.

+1

Funkcja variadic jest bardzo delikatna, ponieważ musi być w stanie poznać dokładny typ i rozmiar wszystkich parametry przekazane do niego i nie może tego wymusić w czasie kompilacji.Jeśli zmienna jest niewłaściwego typu, wron zostanie odczytana wartość g; jeśli jest to niewłaściwy rozmiar, wszystkie zmienne po będą również błędnie przeczytane. Gdyby można było przekazać dwie różne wielkości pływaka, spowodowałoby to wszystkie nieprzyjemne i łatwe do przeoczenia problemy. – mwfearnley

2

Użycie wartości zmiennoprzecinkowej lub podwójnej w wyrażeniu C spowoduje, że wartość będzie podwójna, tak więc printf nie może stwierdzić różnicy. Podczas gdy wskaźnik do podwójnego musi być jawnie zasygnalizowany, aby skanować w odróżnieniu od wskaźnika do pływania, ponieważ to, co wskazuje wskaźnik, jest ważne.

+5

zmienna jest konwertowana na podwójną * w tym przypadku *, ponieważ argumenty są częścią listy argumentów o zmiennej długości, zmienne nie zawsze są konwertowane na podwójne w C. –

+1

W standardowych wersjach języka C wartości 'float' były automatycznie promowane do 'podwójnego' w wyrażeniach. Reguła ta została porzucona w standardzie C. Ogólnie rzecz biorąc, 'float' nie zostaje awansowane do wyrażeń' double' w wyrażeniach. Promowane jest tylko do "podwójnego", gdy przekazywane jest jako argument wariasu, co dzieje się w tym przypadku. – AnT

7

Ponieważ w przeciwnym razie scanf uzna, że ​​podajesz wskaźnik do elementu pływającego, który ma mniejszy rozmiar niż podwójny, i zwróci nieprawidłową wartość.

20

Od С99 dopasowanie między specyfikatorami formatu i zmiennoprzecinkowymi typami argumentów w C jest zgodne między printf i scanf. Jest

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

tak się składa, że ​​gdy argumenty typu float są przekazywane jako parametry o zmiennej liczbie argumentów, takie argumenty są niejawnie konwertowane wpisać double. Z tego powodu specyfikatory formatu printf w formacie %f i %lf są równoważne i wymienne. W printf można "krzyżowo używać" pod numer %lf z float lub %f z double.

Ale nie ma powodu, aby faktycznie to robić w praktyce. Nie używaj argumentów typu %f do printf typu double. Jest to powszechny zwyczaj urodzony w C89/90 razy, ale jest to zły nawyk. Użyj %lf w printf dla double i zachowaj %f zarezerwowane dla argumentów .

+0

Powiedziałbym, że używanie '% f' w printf jest dobrym nawykiem, ponieważ wtedy twój kod zawsze działa, podczas gdy użycie'% lf' może się nie udać, jeśli kompilator nie ma biblioteki zgodnej z C99. Niestety taka sytuacja ma miejsce w rzeczywistości. –

Powiązane problemy