#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 %d
dalam printf
pernyataan untuk mempelajari perilaku printf
.
Itu karena %d
mengharapkan int
tetapi Anda telah menyediakan pelampung.
Gunakan %e
/ %f
/ %g
untuk mencetak float.
Tentang mengapa 0 dicetak: Angka floating point diubah menjadi double
sebelum mengirim ke printf
. Angka 1234,5 dalam representasi ganda di little endian adalah
00 00 00 00 00 4A 93 40
A %d
mengkonsumsi integer 32-bit, jadi nol dicetak. (Sebagai ujian, Anda printf("%d, %d\n", 1234.5f);
bisa mendapatkan hasil 0, 1083394560
.)
Adapun mengapa float
diubah 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
float
dipromosikan kedouble
. Ini disebut promosi argumen default .
(Terima kasih Alok telah menemukan ini.)
printf
merupakan fungsi variadik, dan standar mengatakan bahwa untuk fungsi variadic, afloat
diubah menjadidouble
sebelum meneruskan.printf()
memanggil Undefined Behavior .Secara teknis tidak ada yang
printf
, masing-masing alat perpustakaan sendiri, dan karena itu, metode Anda mencoba untuk studiprintf
's perilaku dengan melakukan apa yang Anda lakukan tidak akan banyak berguna. Anda dapat mencoba mempelajari perilakuprintf
di sistem Anda, dan jika demikian, Anda harus membaca dokumentasi, dan melihat kode sumber untuk mengetahuiprintf
apakah itu tersedia untuk perpustakaan Anda.Misalnya, di Macbook saya, saya mendapatkan output
1606416304
dengan program Anda.Karena itu, saat Anda meneruskan a
float
ke fungsi variadic, makafloat
akan diteruskan sebagai adouble
. Jadi, program Anda sama dengan mendeklarasikana
sebagaidouble
.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
double
ternyata 0, yang mungkin menjadi alasan Anda mendapatkan0
outputprintf
panggilan 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
sumber
int
argumen diteruskan dalam register yang berbeda daridouble
argumen.printf
dengan%d
mengambilint
argumen itu 42 dan yang kedua%d
mungkin mencetak sampah karena tidak adaint
argumen kedua .The
%d
specifier mengatakanprintf
untuk mengharapkan integer. Jadi empat (atau dua, tergantung pada platform) pertama byte float diinterpretasikan sebagai integer. Jika nilainya nol, angka nol akan dicetakRepresentasi biner dari 1234.5 adalah seperti ini
1.00110100101 * 2^10 (exponent is decimal ...)
Dengan kompiler C yang mewakili
float
sebenarnya 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
printf
dicetak ...Lihat artikel Wikipedia ini untuk representasi floating point menurut IEEE754.
sumber
Itu karena representasi float dalam biner. Konversi ke integer meninggalkannya dengan 0.
sumber
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.
sumber
Alasannya adalah itu
printf()
adalah fungsi yang sangat bodoh. Itu tidak memeriksa jenis sama sekali. Jika Anda mengatakan argumen pertama adalahint
(dan ini yang Anda katakan%d
), argumen itu mempercayai Anda dan hanya membutuhkan byte yang diperlukan untuk fileint
. Dalam kasus ini, dengan asumsi mesin Anda menggunakan empat-byteint
dan delapan-bytedouble
(float
diubah menjadi bagiandouble
dalamprintf()
), empat byte pertamaa
hanya akan menjadi nol, dan ini akan dicetak.sumber
Itu tidak akan mengubah float secara otomatis menjadi integer. Karena keduanya memiliki format penyimpanan yang berbeda. Jadi jika Anda ingin mengonversi, gunakan (int) typecasting.
#include <stdio.h> int main() { float a = 1234.5f; printf("%d\n", (int)a); return 0; }
sumber
Karena Anda juga menandainya dengan C ++, kode ini melakukan konversi seperti yang Anda harapkan:
#include <iostream.h> int main() { float a = 1234.5f; std::cout << a << " " << (int)a << "\n"; return 0; }
Keluaran:
1234.5 1234
sumber
%d
adalah desimal%f
mengambanglihat lebih banyak di sini .
Anda mendapatkan 0 karena float dan integer direpresentasikan secara berbeda.
sumber
Anda hanya perlu menggunakan penentu format yang sesuai (% d,% f,% s, dll.) Dengan tipe data yang relevan (int, float, string, dll.).
sumber
Anda ingin% f bukan% d
sumber
hey itu harus mencetak sesuatu sehingga mencetak 0. Ingat di C 0 adalah segalanya!
sumber
Ini bukan bilangan bulat. Coba gunakan
%f
.sumber