2011-10-12 28 views
9

GCC cảnh báo tôi rằng đoạn mã sau đây có chứa một chuyển đổi ngầm có thể thay đổi một giá trị:Tại sao GCC cảnh báo chống lại sự chuyển đổi tiềm ẩn này?

#include <stdlib.h> 
float square = rand(); 

Tuy nhiên, sau đây không mang lại bất kỳ cảnh báo:

float square = 100; 

Cảnh báo được đưa ra bởi GCC là như sau:

tests/ChemTests.cpp:17:23: error: conversion to ‘float’ from ‘int’ may alter its value 

Tôi không hiểu tại sao trước đây sẽ đưa ra cảnh báo, vì rand() là p roperly tuyên bố và trả về một số int, giống như số nguyên là 100.

Tại sao dòng đầu tiên đưa ra cảnh báo trình biên dịch chứ không phải là cảnh báo thứ hai, mặc dù cả hai đều có chuyển đổi ẩn từ int sang float?

+0

Tôi thấy rằng tôi không nhận được cảnh báo trừ khi tôi sử dụng tùy chọn '-Wconversion'. –

Trả lời

14

GCC phát ra cảnh báo này khi mất độ chính xác có thể do dàn diễn viên. (nói cách khác, giá trị có thể được "thay đổi")

Trong trường hợp đầu tiên, rand() trả về một int. Vì không phải tất cả các giá trị có thể được lưu trữ trong một số int đều có thể đại diện là float, nó sẽ phát ra cảnh báo này.

Trong trường hợp thứ hai, 100 có thể được đúc an toàn thành float mà không bị mất chính xác.

+0

Điều này có nghĩa là 'float f = 123456789' sẽ đưa ra lỗi? –

+0

Nó sẽ không lỗi, nhưng nó sẽ đưa ra một cảnh báo. Tôi không có GCC ở phía trước của tôi thời điểm này, nhưng tôi chỉ thử nghiệm nó trong Visual Studio và nó đưa ra một cảnh báo: 'cảnh báo C4305: 'khởi tạo': cắt ngắn từ 'int' thành 'float'' – Mysticial

5

Để thêm nội dung nào đó vào những gì Mysticial đã viết (chính xác): việc bạn triển khai C sử dụng float32 bits IEEE 754 single precision binary floating-pointint là 32 bit. Trong "của bạn" int bạn có thể có 31 bit số và 1 bit dấu. Trong "của bạn" float mantissa là 24 bit và có 1 bit dấu. Rõ ràng int s cần nhiều hơn 24 bit cộng với dấu hiệu được biểu diễn không thể được chuyển đổi chính xác thành "của bạn" float. (Tôi sử dụng "của bạn" để đại diện cho "của bạn" trình biên dịch, trình biên dịch bạn đang sử dụng.Các tiêu chuẩn C không cho biết chiều dài chính xác của float hoặc int).

Bây giờ, rand() có thể tạo ra bất kỳ số int nào, do đó trình biên dịch phải cung cấp cho bạn cảnh báo. 100 là một chữ số được biết đến tại thời gian biên dịch, do đó trình biên dịch có thể kiểm tra tĩnh nếu số đó có thể chuyển đổi được hay không.

(thậm chí không giải thích chính xác cách các điểm nổi hoạt động, int của bạn là 32 bit và "chỉ hỗ trợ" các số nguyên. float của bạn là 32 bit và "hỗ trợ" số dấu phẩy động. bạn phải lưu một nơi nào đó có dấu thập phân), do đó, phải có một "giá" bạn phải trả nếu cả hai số intfloat có cùng độ dài. Giá chính xác.)

Để trả lời nhận xét bạn đã tạo, số lượng tối đa bạn có thể đại diện chính xác trong một số float là "tiếp giáp" tới 0 (để 0 ... tất cả đều chính xác được thể hiện) là 16777215 (có mantissa = 16777215 và exp onent = 0) và 16777216 (có mantissa = 1 và số mũ = 24, vì nó là 1 * 2^24). 16777217 không thể đại diện chính xác. 16777218 là.

0

Không phải mọi int đều có thể được thể hiện dưới dạng float. Cụ thể, nếu số bit giữa bit cao nhất và thấp nhất được đặt trong một số int lớn hơn FLT_MANT_DIG - 1, được xác định trong <float.h>, thì không thể đại diện chính xác như là float. Trình biên dịch cảnh báo bạn rằng có khả năng mất chính xác tiềm năng bởi vì việc khai báo rand() có nghĩa là rand() có thể trả lại bất kỳ int nào, bao gồm cả những số không thể được biểu diễn là float.

gcc nên là đủ để biết thông minh khi int literals thể được biểu diễn một cách chính xác:

float f= 1<<FLT_MANT_DIG; // yes 
float g= (1<<FLT_MANT_DIG) - 1; // yes 
float h= (1<<FLT_MANT_DIG) + 1; // no 
float i= (1<<(FLT_MANT_DIG + 1)); // yes 

gcc nên nhổ ra một cảnh báo cho chỉ khởi h.

Ngẫu nhiên, nếu RAND_MAX nhỏ hơn hoặc bằng (1<<FLT_MANT_DIG) - 1, bạn có thể chuyển an toàn rand() tới float, ngay cả khi trình biên dịch phàn nàn với bạn.

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