Почему GCC предостерегает от этого неявного преобразования? - PullRequest
9 голосов
/ 12 октября 2011

GCC предупреждает меня о том, что следующий фрагмент кода содержит неявное преобразование, которое может изменить значение:

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

Однако следующее не выдает никакого предупреждения:

float square = 100;

GCC выдает следующее предупреждение:

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

Я не понимаю, почему первый выдаст предупреждение, поскольку rand() правильно объявлен и возвращает int, так же как 100 целочисленный литерал.

Почему первая строка выдает предупреждение компилятора, а не вторую, хотя обе имеют неявное преобразование из int в float?

Ответы [ 3 ]

14 голосов
/ 12 октября 2011

GCC выдает это предупреждение, когда из-за приведения может произойти потеря точности. (другими словами, значение может быть «изменено»)

В первом случае rand() возвращает int. Поскольку не все значения, которые могут быть сохранены в int, могут быть представлены как float, оно выдаст это предупреждение.

Во втором случае 100 можно безопасно преобразовать в float без потери точности.

5 голосов
/ 12 октября 2011

Чтобы добавить что-то к тому, что написал Mysticial (это правильно): ваша реализация C использует float, которые 32 бита, двоичные числа с плавающей точкой одинарной точности IEEE 754 и int, которые являются 32 битами,В «вашем» int вы можете иметь 31 бит числа и 1 бит знака.В «вашем» float значение mantissa составляет 24 бита и 1 бит знака.Ясно, что int s, для представления которых требуется более 24 бит плюс знак, не может быть точно преобразовано в "ваше" float.(Я использую «your» для представления «вашего» компилятора, компилятора, который вы используете. Стандарт C не указывает точную длину float или int).

Теперь, rand() может генерировать любое число int, поэтому компилятор должен предупредить вас.100 - это числовой литерал, который известен во время компиляции, поэтому компилятор может статически проверить, может ли это число быть конвертируемым.

(даже без точного объяснения того, как работают числа с плавающей запятой, ваш int равен 32 битам).и «поддерживает» только целые числа. Ваш float является 32-битным и «поддерживает» числа с плавающей запятой. Ясно, что числа с плавающей запятой труднее представить (вы должны сохранить где-нибудь, где находится десятичная точка), поэтому должен быть«цена», которую вы платите, если оба значения int и float имеют одинаковую длину. Цена является точной.)

Чтобы ответить на сделанный вами комментарий, максимальное число, которое вы можете представить точно в float то есть "смежно" с 0 (так что 0 ... число все точно представимо) - это 16777215 (у которого есть мантисса = 16777215 и экспонента = 0) и 16777216 (у которого есть мантисса = 1 и экспонента = 24, потому что это 1* 2 ^ 24).16777217 точно не представлен.16777218 is.

0 голосов
/ 12 октября 2011

Не каждый int может быть представлен как float.В частности, если число битов между старшим и младшим битами, установленными в int, больше, чем FLT_MANT_DIG - 1, определенное в <float.h>, оно не может быть точно представлено как float.(То же самое относится к double и DBL_MANT_DIG - 1.) Компилятор предупреждает вас о потенциальной потере точности, поскольку объявление rand() означает, что rand() может вернуть любой int, включая те, которые не могут быть представлены какfloat.

gcc должен быть достаточно умен, чтобы знать, когда литералы int могут быть представлены точно:

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 должен выдать предупреждение только для инициализации h.

Кстати, если RAND_MAX меньше или равно (1<<FLT_MANT_DIG) - 1, вы можете безопасно назначить rand() для float, даже если компилятор жаловался вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...