Mengapa scanf () membutuhkan "% lf" untuk dobel, ketika printf () tidak apa-apa hanya dengan "% f"?

179

Mengapa itu scanf()perlu l" %lf" di saat membaca double, kapan printf()bisa menggunakan " %f" terlepas dari apakah argumennya adalah a doubleatau a float?

Kode contoh:

double d;
scanf("%lf", &d);
printf("%f", d);
raldi
sumber
1
Saya tidak mengerti apa yang Anda maksud dengan POINTER di sini. Dalam scanf kami hanya meneruskan & variabel (yaitu) alamat jadi di mana pointer
7
@deetchanya Di C, ketika Anda "mengambil alamat" variabel dengan &operator unary , hasil operasi itu adalah penunjuk ke lokasi penyimpanan variabel dalam memori. Ini adalah pointer yang diteruskan ke scanf.
zwol
ini adalah pos lain mengenai stackoverflow.com/questions/9291348/…
vimalpt

Jawaban:

207

Karena C akan mempromosikan floats ke doubles untuk fungsi yang mengambil argumen variabel. Pointer tidak dipromosikan ke apa pun, jadi Anda harus menggunakan %lf, %lgatau %le(atau %ladalam C99) untuk membaca ganda.

MSN
sumber
26

Sejak С99 pencocokan antara penentu format dan tipe argumen floating-point dalam C konsisten antara printfdan scanf. ini

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

Kebetulan ketika argumen tipe floatdilewatkan sebagai parameter variadic, argumen tersebut secara implisit dikonversi menjadi tipe double. Ini adalah alasan mengapa dalam printfpenspesifikasi format %fdan %lfsetara dan dipertukarkan. Di dalam printfAnda dapat "cross-use" %lfdengan floatatau %fdengan double.

Tetapi tidak ada alasan untuk benar-benar melakukannya dalam praktik. Jangan gunakan %funtuk printfargumen tipe double. Ini adalah kebiasaan yang tersebar luas yang lahir kembali di tahun C89 / 90, tetapi itu adalah kebiasaan buruk. Gunakan %lfdi printfuntuk doubledan terus %fdicadangkan untuk floatargumen.

Semut
sumber
1
Saya akan mengatakan bahwa menggunakan %fdi printf adalah kebiasaan yang baik karena kode Anda selalu berfungsi, sedangkan menggunakan %lfmungkin gagal jika kompiler tidak memiliki perpustakaan yang sesuai dengan C99. Sayangnya situasi itu memang terjadi dalam kenyataan.
MM
Sejak С99 pencocokan antara penentu format dan tipe argumen floating-point dalam C konsisten antara printfdan scanf. Perhatikan bahwa ini tidak menyiratkan bahwa menggunakan specifier format yang sama berarti bahwa data yang ditulis oleh a [f]printf()dapat dibaca oleh [f]scanf(). Secara umum, menggunakan specifier format yang sama untuk scanf()yang digunakan oleh tidakprintf() akan berhasil membaca data. Misalnya, ruang bantalan yang dapat dimasukkan oleh penentu format format akan dilewati oleh penentu format format yang sama dalam panggilan. prinf()"%d""%d"scanf()
Andrew Henle
16

scanfperlu mengetahui ukuran data yang ditunjuk oleh &duntuk mengisinya dengan benar, sedangkan fungsi variadic mempromosikan floats menjadi ganda (tidak sepenuhnya yakin mengapa), jadi printfselalu mendapatkan a double.

Tanktalus
sumber
1
Fungsi variadic sangat rapuh, karena itu harus dapat mengetahui jenis dan ukuran yang tepat dari semua parameter yang diteruskan ke sana, dan itu tidak dapat menegakkan ini pada waktu kompilasi. Jika variabel adalah tipe yang salah, nilai yang salah akan dibaca; jika ukurannya salah, semua variabel sesudahnya juga akan salah dibaca. Jika dua ukuran pelampung yang berbeda dapat dilewati, maka itu akan menyebabkan semua jenis masalah yang buruk dan mudah terlewatkan.
mwfearnley
7

Karena jika tidak, scanf akan berpikir Anda melewatkan pointer ke float yang ukurannya lebih kecil daripada double, dan itu akan mengembalikan nilai yang salah.

Jim Buck
sumber
2

Menggunakan float atau nilai ganda dalam ekspresi C akan menghasilkan nilai yang merupakan nilai ganda, sehingga printf tidak dapat membedakannya. Sedangkan pointer ke double harus secara eksplisit ditandai untuk memindai sebagai berbeda dari pointer ke float, karena apa yang menunjuk pointer adalah yang penting.

fcw
sumber
5
float dikonversi menjadi dobel dalam kasus ini karena argumen adalah bagian dari daftar argumen panjang variabel, float tidak selalu dikonversi menjadi ganda dalam C.
Robert Gamble
1
Dalam versi pra-standar floatnilai-nilai bahasa C secara otomatis dipromosikan ke doubledalam ekspresi. Aturan itu ditinggalkan dalam standar C. Secara umum, floattidak dipromosikan ke doubledalam ekspresi. Itu hanya akan dipromosikan doubleketika disahkan sebagai argumen variadic, yang adalah apa yang terjadi dalam kasus ini.
AnT