#include <stdio.h>
int main() {
float a = 1234.5f;
printf("%d\n", a);
return 0;
}
Ini menampilkan 0!! Bagaimana mungkin? Apa alasannya?
Saya sengaja meletakkan %ddalam printfpernyataan untuk mempelajari perilaku printf.
Jawaban:
Itu karena %dmengharapkan inttetapi Anda telah menyediakan pelampung.
Gunakan %e/ %f/ %guntuk mencetak float.
Tentang mengapa 0 dicetak: Angka floating point diubah menjadi doublesebelum mengirim ke printf. Angka 1234,5 dalam representasi ganda di little endian adalah
00 00 00 00 00 4A 93 40
A %dmengkonsumsi integer 32-bit, jadi nol dicetak. (Sebagai ujian, Anda printf("%d, %d\n", 1234.5f);bisa mendapatkan hasil 0, 1083394560.)
Adapun mengapa floatdiubah menjadi double, seperti prototipe printf int printf(const char*, ...), dari 6.5.2.2/7,
Notasi elipsis dalam deklarator prototipe fungsi menyebabkan konversi tipe argumen berhenti setelah parameter yang terakhir dideklarasikan. Promosi argumen default dilakukan pada argumen trailing.
dan dari 6.5.2.2/6,
Jika ekspresi yang menunjukkan fungsi yang dipanggil memiliki tipe yang tidak menyertakan prototipe, promosi integer dilakukan pada setiap argumen, dan argumen yang memiliki tipe
floatdipromosikan kedouble. Ini disebut promosi argumen default .
(Terima kasih Alok telah menemukan ini.)
printfmerupakan fungsi variadik, dan standar mengatakan bahwa untuk fungsi variadic, a floatdiubah menjadi doublesebelum meneruskan.
printf()memanggil Undefined Behavior .
Secara teknis tidak ada yang printf , masing-masing alat perpustakaan sendiri, dan karena itu, metode Anda mencoba untuk studi printf's perilaku dengan melakukan apa yang Anda lakukan tidak akan banyak berguna. Anda dapat mencoba mempelajari perilaku printfdi sistem Anda, dan jika demikian, Anda harus membaca dokumentasi, dan melihat kode sumber untuk mengetahui printfapakah itu tersedia untuk perpustakaan Anda.
Misalnya, di Macbook saya, saya mendapatkan output 1606416304dengan program Anda.
Karena itu, saat Anda meneruskan a floatke fungsi variadic, maka floatakan diteruskan sebagai a double. Jadi, program Anda sama dengan mendeklarasikan asebagai double.
Untuk memeriksa byte dari a double, Anda dapat melihat jawaban untuk pertanyaan terbaru ini di SO.
Ayo lakukan itu:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
unsigned char *p = (unsigned char *)&a;
size_t i;
printf("size of double: %zu, int: %zu\n", sizeof(double), sizeof(int));
for (i=0; i < sizeof a; ++i)
printf("%02x ", p[i]);
putchar('\n');
return 0;
}
Ketika saya menjalankan program di atas, saya mendapatkan:
size of double: 8, int: 4
00 00 00 00 00 4a 93 40
Jadi, empat byte pertama doubleternyata 0, yang mungkin menjadi alasan Anda mendapatkan 0output printfpanggilan Anda .
Untuk hasil yang lebih menarik, kita bisa sedikit mengubah programnya:
#include <stdio.h>
int main(void)
{
double a = 1234.5f;
int b = 42;
printf("%d %d\n", a, b);
return 0;
}
Ketika saya menjalankan program di atas di Macbook saya, saya mendapatkan:
42 1606416384
Dengan program yang sama di mesin Linux, saya mendapatkan:
0 1083394560
intargumen diteruskan dalam register yang berbeda dari doubleargumen. printfdengan %dmengambil intargumen itu 42 dan yang kedua %dmungkin mencetak sampah karena tidak ada intargumen kedua .
The %dspecifier mengatakan printfuntuk mengharapkan integer. Jadi empat (atau dua, tergantung pada platform) pertama byte float diinterpretasikan sebagai integer. Jika nilainya nol, angka nol akan dicetak
Representasi biner dari 1234.5 adalah seperti ini
1.00110100101 * 2^10 (exponent is decimal ...)
Dengan kompiler C yang mewakili floatsebenarnya sebagai nilai ganda IEEE754, byte akan (jika saya tidak membuat kesalahan)
01000000 10010011 01001010 00000000 00000000 00000000 00000000 00000000
Pada sistem Intel (x86) dengan sedikit endianess (yaitu byte paling signifikan datang lebih dulu), urutan byte ini dibalik sehingga empat byte pertama adalah nol. Artinya, apa yang printfdicetak ...
Lihat artikel Wikipedia ini untuk representasi floating point menurut IEEE754.
Itu karena representasi float dalam biner. Konversi ke integer meninggalkannya dengan 0.
Karena Anda memanggil perilaku tidak terdefinisi: Anda melanggar kontrak metode printf () dengan berbohong kepadanya tentang tipe parameternya, sehingga kompilator bebas melakukan apa pun yang diinginkannya. Itu bisa membuat keluaran program "dksjalk is a ninnyhead !!!" dan secara teknis itu masih benar.
Alasannya adalah itu printf()adalah fungsi yang sangat bodoh. Itu tidak memeriksa jenis sama sekali. Jika Anda mengatakan argumen pertama adalah int(dan ini yang Anda katakan %d), argumen itu mempercayai Anda dan hanya membutuhkan byte yang diperlukan untuk file int. Dalam kasus ini, dengan asumsi mesin Anda menggunakan empat-byte intdan delapan-byte double( floatdiubah menjadi bagian doubledalam printf()), empat byte pertama ahanya akan menjadi nol, dan ini akan dicetak.
%d adalah desimal
%f mengambang
lihat lebih banyak di sini .
Anda mendapatkan 0 karena float dan integer direpresentasikan secara berbeda.
Anda hanya perlu menggunakan penentu format yang sesuai (% d,% f,% s, dll.) Dengan tipe data yang relevan (int, float, string, dll.).
Ini bukan bilangan bulat. Coba gunakan %f.