2011-10-15 37 views
13

Thật đáng ngạc nhiên khi tôi thấy rằng ngay cả khi giá trị có thể được chuyển đổi, chuyển đổi int sang float luôn luôn cảnh báo. Tại sao điều này?int để chuyển đổi float tạo ra một cảnh báo?

int i = 0; 
float f = 0; // warning here 

// I thought this was an implicit conversion, 
// meaning it is convertible with no warnings. 
f = i;  // another warning here 

Cảnh báo là:

warning C4244: '=' : conversion from 'int' to 'float', possible loss of data 
+1

Gán giá trị MAX INT cho loại phao và xem kết quả. –

+3

float f = 0.0f; // 0 là số nguyên. –

+0

Nó đưa ra cảnh báo tương tự với cả 'f = MAXINT;' và 'f = INT_MAX; ' – user103214

Trả lời

4

tôi đã trả lời một câu hỏi tương tự ở đây:

Why does GCC warn against this implicit conversion?

Nguyên nhân là do một int cần phải được làm tròn khi nó được đúc thành một floatfloat không được chứa tất cả độ chính xác của int trong ca này se.

Trong trường hợp của bạn, float chỉ có khoảng 24 bit chính xác. Trong khi một int có 32 bit chính xác, do đó, một số độ chính xác là mất bởi dàn diễn viên này, do đó cảnh báo.

+0

Có thể có (và) triển khai' float' có thể giữ tất cả các giá trị của kiểu 'int' mà không mất thông tin - ví dụ nếu' int' và 'float' là 16 và 32 bit, tương ứng, hoặc 32 và 64 bit. Nhưng các trình biên dịch tất nhiên là miễn phí để sử dụng thông tin về việc triển khai cụ thể khi quyết định đưa ra cảnh báo. –

+0

Tôi nhận ra rằng, do đó tôi đã chèn "trong trường hợp này" vào câu trả lời của tôi vì nó không được xác định là phổ quát đúng. – Mysticial

10

Tùy thuộc vào số lượng bit bạn có trong loại int. Một phao có độ chính xác đơn IEEE754 là giá trị 32 bit nhưng một số bit được gán cho số mũ, có nghĩa là không phải tất cả đều có sẵn cho độ chính xác.

Nếu loại int của bạn có độ chính xác cao hơn float, thì bạn có thể bị mất chính xác ở mức cao nhất.

Nói cách khác, nó có thể không phân biệt được giữa INT_MAXINT_MAX - 1.

Giải pháp trong trường hợp đó là sử dụng loại dấu phẩy động rộng hơn (double) mặc dù, về mặt kỹ thuật, bạn có thể tìm thấy triển khai có loại 2562 bit int trong trường hợp này bạn sẽ phải tìm cách khác :-)

This answer có tổng quan ngắn gọn về cách các định dạng điểm nổi hoạt động, bao gồm thực tế là chỉ có 23 trong số 32 bit có sẵn cho độ chính xác của phần định trị.

3

Chỉ cần cho vui, thử điều này và xem những gì đầu ra là (gợi ý, bạn mong chờ các con số để tất cả được như vậy, phải không?):

int i1(INT_MAX), i2; 

float f(i1); 

i2 = f; 

std::cout << i1 << ' ' << f << ' ' << i2 << '\n'; 

Vâng, câu trả lời tôi nhận được là:

2147483647 2.14748e+009 -2147483648 

vì vậy, trình biên dịch là hoàn toàn đúng chỉ ra rằng một cái gì đó có thể đi sai với các diễn viên, nhưng nó không phải là đủ thông minh để biết chắc chắn, bởi vì nó sẽ chỉ có xu hướng xảy ra ở hai cực phạm vi số. Nó luôn luôn tốt nhất để static_cast <> theo quan điểm của tôi, cho rõ ràng ít nhất, và để hiển thị trình biên dịch rằng đó là những gì bạn dự định.

Bằng cách này tôi không hoàn toàn chắc chắn lý do tại sao kết quả trên xảy ra. Có lẽ ai đó khác có thể giải thích!

+0

Nó mang lại cho tôi hai cảnh báo, một cảnh báo về việc khởi động phao và một lần chuyển sang nổi. – user103214

+0

@ user974191: Điều đó không rõ ràng từ câu hỏi ban đầu của bạn. Tôi đã cập nhật nó để phản ánh thông tin đó (mặc dù tôi hơi ngạc nhiên khi nó cảnh báo về 'float f = 0;'). Vui lòng xem lại các chỉnh sửa của tôi. –

1

// Tôi nghĩ đây là chuyển đổi ngầm nghĩa là nó có thể chuyển đổi với không có cảnh báo?

Không, đó không phải là ý nghĩa của nó. Nó chỉ có nghĩa là bạn có thể gán giá trị của một loại cho một đối tượng thuộc loại khác mà không có chuyển đổi rõ ràng (nghĩa là, một diễn viên) và giá trị sẽ được chuyển đổi hoàn toàn.

Và trong trường hợp này, cảnh báo có thể phù hợp. Nếu intfloat đều 32 bit (đó là điển hình nhưng không phổ biến), sau đó tất cả các giá trị của loại int nằm trong phạm vi của float, nhưng có rất nhiều giá trị của loại int mà không thể được đại diện chính xác trong loại float.

Chuẩn ngôn ngữ yêu cầu ít nhất một thông báo chẩn đoán cho bất kỳ đơn vị dịch nào (tệp nguồn) vi phạm quy tắc cú pháp hoặc ràng buộc. Nhưng trình biên dịch được tự do phát hành chẩn đoán bổ sung mà họ thích.

+0

Có một hạn chế quan trọng đối với chẩn đoán trình biên dịch bổ sung - trình biên dịch không thể đưa ra nhiều chẩn đoán như vậy để không thể biên dịch chương trình tuân thủ tiêu chuẩn. Đã có một số trình biên dịch (không biết nếu có vẫn còn) mà sẽ chết nếu một dòng sản xuất quá nhiều cảnh báo. Mặc dù sẽ không bình thường đối với một dòng để tạo ra hàng nghìn cảnh báo, nó sẽ có thể cho một chương trình tiêu chuẩn để làm như vậy với các mở rộng macro. – supercat

+0

@supercat: Điều đó áp dụng như nhau đối với bất kỳ thứ gì mà trình biên dịch thực hiện, không chỉ là chẩn đoán. Những gì bạn mô tả chỉ là một lỗi trình biên dịch; bình thường phát hành cảnh báo gazillion umpteen sẽ không gây ra một trình biên dịch để sụp đổ. Và tiêu chuẩn cho phép các trình biên dịch thất bại do giới hạn dung lượng; nó chỉ yêu cầu nó dịch và thực hiện một chương trình * duy nhất đạt tới tất cả các giới hạn đã chỉ định (C99 5.2.4.1). –

Các vấn đề liên quan