Off đầu tiên, như đề cập đến trong một số câu trả lời khác nhưng không, để tâm trí của tôi, nêu ra rõ ràng đủ: Nó không làm việc để cung cấp một số nguyên trong hầu hết các tình huống nơi một chức năng thư viện mất một double
hoặc float
tranh cãi. Trình biên dịch sẽ tự động chèn một chuyển đổi. Ví dụ, sqrt(0)
được định nghĩa rõ ràng và sẽ hoạt động chính xác sqrt((double)0)
, và điều này cũng đúng với bất kỳ biểu thức kiểu số nguyên nào khác được sử dụng ở đó.
printf
khác. Nó khác vì nó có một số lượng đối số thay đổi. Nguyên mẫu chức năng của nó là
extern int printf(const char *fmt, ...);
Do đó, khi bạn viết
printf(message, 0)
trình biên dịch không có bất kỳ thông tin nào về kiểu printf
mong đợi đối số thứ hai đó là. Nó chỉ có kiểu của biểu thức đối số, nghĩa là int
sẽ chạy qua. Do đó, không giống như hầu hết các hàm thư viện, lập trình viên phụ thuộc vào bạn để đảm bảo danh sách đối số phù hợp với mong đợi của chuỗi định dạng.
(Các trình biên dịch hiện đại có thể xem xét một chuỗi định dạng và cho bạn biết rằng bạn có một loại không khớp, nhưng họ sẽ không bắt đầu chèn các chuyển đổi để hoàn thành ý bạn, vì tốt hơn là mã của bạn nên ngắt ngay bây giờ, khi bạn nhận thấy , hơn nhiều năm sau khi được xây dựng lại bằng một trình biên dịch ít hữu ích hơn.)
Bây giờ, nửa còn lại của câu hỏi là: Cho rằng (int) 0 và (float) 0.0, trên hầu hết các hệ thống hiện đại, cả hai đều được biểu diễn dưới dạng 32 bit, tất cả đều bằng 0, tại sao nó không hoạt động một cách tình cờ? Tiêu chuẩn C chỉ nói rằng "điều này không bắt buộc phải hoạt động, bạn tự làm", nhưng hãy để tôi giải thích hai lý do phổ biến nhất khiến nó không hoạt động; điều đó có thể sẽ giúp bạn hiểu tại sao nó không bắt buộc.
Thứ nhất, vì những lý do lịch sử, khi bạn vượt qua một float
thông qua một danh sách đối số biến nó được khuyến khích để double
, trong đó, trên hầu hết các hệ thống hiện đại, là 64 bit rộng. Vì vậy, printf("%f", 0)
chỉ chuyển 32 bit 0 cho một bộ nhớ mong đợi 64 bit trong số đó.
Lý do thứ hai, quan trọng không kém là các đối số của hàm dấu phẩy động có thể được chuyển vào một nơi khác với các đối số nguyên. Ví dụ: hầu hết các CPU đều có tệp thanh ghi riêng biệt cho số nguyên và giá trị dấu phẩy động, vì vậy có thể là một quy tắc mà các đối số từ 0 đến 4 đi trong các thanh ghi r0 đến r4 nếu chúng là số nguyên, nhưng f0 đến f4 nếu chúng là dấu phẩy động. Vì vậy, hãy printf("%f", 0)
tìm trong thanh ghi f1 cho số 0 đó, nhưng nó hoàn toàn không có ở đó.
printf
đang mong đợi mộtdouble
, và bạn đang cho nó mộtint
.float
vàint
có thể có cùng kích thước trên máy của bạn, nhưng0.0f
thực sự được chuyển đổi thành adouble
khi được đẩy vào danh sách đối số khác nhau (vàprintf
mong đợi điều đó). Nói tóm lại, bạn đang không thực hiện được thỏa thuận cuối cùngprintf
dựa trên các thông số kỹ thuật mà bạn đang sử dụng và các lập luận bạn đang cung cấp.