Penentu format yang benar untuk mencetak dua kali dalamf


482

Untuk apa specifier format yang benar doubledalam printf? Apakah itu %fatau tidak %lf? Saya percaya itu %f, tapi saya tidak yakin.

Contoh kode

#include <stdio.h>

int main()
{
   double d = 1.4;
   printf("%lf", d); // Is this wrong?
}

19
Jika Anda terjebak dengan pustaka C89, "%lf"tidak terdefinisi; di perpustakaan C99 dan C11 itu didefinisikan sama dengan "%f".
pmg

1
Varian Anda sama benarnya dengan yang pernah ada. %lfadalah penentu format yang benar untuk double. Tapi itu jadi di C99. Sebelum itu orang harus menggunakan %f.
AnT

Jawaban:


626

"%f"adalah (atau setidaknya satu) format yang benar untuk double. Ada yang ada format untuk float, karena jika Anda mencoba untuk lulus floatuntuk printf, itu akan dipromosikan ke doublesebelum printfmenerimanya 1 . "%lf"juga dapat diterima di bawah standar saat ini - yang lditentukan tidak berpengaruh jika diikuti oleh fspecifier konversi (antara lain).

Perhatikan bahwa ini adalah satu tempat printfstring format berbeda secara substansial dari string format scanf(dan fscanf, dll.). Untuk output, Anda melewati sebuah nilai , yang akan dipromosikan dari floatke doubleketika lulus sebagai parameter variadic. Untuk input Anda melewati pointer , yang tidak dipromosikan, jadi Anda harus memberi tahu scanfapakah Anda ingin membaca a floatatau double, jadi untuk scanf, %fberarti Anda ingin membaca floatdan %lfberarti Anda ingin membaca double(dan, untuk apa itu layak, untuk a long double, Anda gunakan %Lfuntuk salah satu printfatau scanf).


1. C99, §6.5.2.2 / 6: "Jika ekspresi yang menunjukkan fungsi yang dipanggil memiliki tipe yang tidak termasuk prototipe, promosi integer dilakukan pada setiap argumen, dan argumen yang memiliki tipe float dipromosikan menjadi dua kali lipat. Ini disebut promosi argumen default. " Dalam C ++ kata-katanya agak berbeda (misalnya, itu tidak menggunakan kata "prototipe") tetapi efeknya sama: semua parameter variadic mengalami promosi default sebelum diterima oleh fungsi.


8
Perhatikan bahwa g++tolak %lfketika kompilasi dengan -Wall -Werror -pedantic:error: ISO C++ does not support the ‘%lf’ gnu_printf format
kynan

2
@kynan: Jika demikian (setidaknya dengan mengasumsikan versi g ++ saat ini), itu adalah bug di g ++. Untuk C89 / 90 dan C ++ 98/03, memungkinkan ladalah ekstensi. Standar C99 / 11 dan C ++ 11 membutuhkan implementasi untuk memungkinkannya.
Jerry Coffin

1
Anehnya, scanf memang ingin doublediwakili oleh %lf: ia mengeluh bahwa ia diharapkan float *dan ditemukan double *dengan adil %f.
Eric Dand

1
@JerryCoffin g ++ masih default ke mode g ++ 98
MM

5
@EricDand Itu karena scanfmembutuhkan pointer ke mana untuk menyimpan apa yang dibaca, sehingga kebutuhan untuk mengetahui seberapa besar ruang yang menunjuk-di adalah, sedangkan printfmengambil nilai-nilai mereka sendiri, dan "argumen promosi default" berarti baik akhir sebagai doubles, sehingga ladalah pada dasarnya opsional.
TripeHound

63

Mengingat standar C99 (yaitu, draft N1256 ), aturan bergantung pada jenis fungsi: fprintf (printf, sprintf, ...) atau scanf.

Berikut adalah bagian yang relevan yang diekstraksi:

Kata pengantar

Edisi kedua ini membatalkan dan menggantikan edisi pertama, ISO / IEC 9899: 1990, sebagaimana telah diubah dan diperbaiki oleh ISO / IEC 9899 / COR1: 1994, ISO / IEC 9899 / AMD1: 1995, dan ISO / IEC 9899 / COR2: 1996. Perubahan besar dari edisi sebelumnya meliputi:

  • %lf specifier konversi diizinkan masuk printf

7.19.6.1 fprintfFungsi

7 Pengubah panjang dan artinya adalah:

l (ell) Menentukan bahwa (...) tidak memengaruhi penentu konversi a, A, e, E, f, F, g, atau G berikut.

L Menentukan bahwa penentu konversi konversi a, A, e, E, f, F, g, atau G berlaku untuk argumen ganda yang panjang.

Aturan yang sama ditentukan untuk fprintfmelamar printf, sprintfdan fungsi serupa.

7.19.6.2 fscanfFungsi

11 Pengubah panjang dan artinya adalah:

l (ell) Menentukan bahwa (...) yang menjadi penentu konversi konversi a, A, e, E, f, F, g, atau G berlaku untuk argumen dengan penunjuk tipe menjadi dua kali lipat;

L Menentukan bahwa penentu konversi konversi a, A, e, E, f, F, g, atau G berlaku untuk argumen dengan penunjuk tipe ke panjang ganda.

12 Penentu konversi dan artinya adalah: a, e, f, g Cocok dengan angka floating-point yang ditandatangani secara opsional, (...)

14 Penentu konversi A, E, F, G, dan X juga valid dan berperilaku sama seperti, masing-masing, a, e, f, g, dan x.

Singkat cerita, untuk fprintfpenentu berikut dan jenis yang sesuai ditentukan:

  • %f -> dobel
  • %Lf -> panjang ganda.

dan untuk fscanfitu adalah:

  • %f -> mengapung
  • %lf -> dobel
  • %Lf -> panjang ganda.

25

Bisa jadi %f, %gatau %etergantung pada bagaimana Anda ingin nomor diformat. Lihat di sini untuk detail lebih lanjut. The lpengubah diperlukan scanfdengan double, tapi tidak di printf.


1
-1: lpengubah (huruf kecil) untuk tipe integer ( cplusplus.com/reference/clibrary/cstdio/printf ), dan Luntuk tipe floating point. Selain itu, Lpengubah mengharapkan a long double, bukan polos double.
user470379

10
user470379: Jadi di mana kontradiksi dengan jawaban saya? Bukankah saya mengatakan bahwa ltidak diperlukan printfuntuk double.
vitaut

16

Format %lfadalah printfformat yang benar-benar benar double, persis seperti yang Anda gunakan. Tidak ada yang salah dengan kode Anda.

Format %lfdalam printftidak didukung dalam versi bahasa C lama (pra-C99), yang menciptakan "inkonsistensi" dangkal antara penentu format untuk doubledi printfdan scanf. Ketidakkonsistenan dangkal itu telah diperbaiki di C99.

Anda tidak diharuskan untuk menggunakan %lfdengan doubledi printf. Anda dapat menggunakan %fjuga, jika Anda lebih suka ( %lfdan %fsetara dengan printf). Tetapi dalam C modern sangat masuk akal untuk lebih suka menggunakan %fdengan float, %lfdengan doubledan %Lfdengan long double, secara konsisten dalam keduanya printfdan scanf.


Dengan scanf(), "%f", "%lf"cocok dengan float *, double *, tidak float, doubleseperti yang tersirat oleh baris terakhir.
chux - Reinstate Monica

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.