V674. Expression contains a suspicious mix of integer and real types.
Анализатор обнаружил потенциальную ошибку в выражении, где совместно используются целочисленные и real-типы данных. Под real-типами понимаются такие типы, как float/double/long double.
Рассмотрим для начала самый простой случай. Литерал, имеющий тип 'double' неявно приводится к целочисленному типу. Это может указывать на наличии программной ошибки.
int a = 1.1;
Этот код не имеет практического смысла. Скорее всего, переменная должна была быть инициализирована другим значением.
Показанный выше пример надуманный и не интересен. Давайте посмотрим, как проявляет себя эта ошибка на практике.
Пример 1.
int16u object_layer_width;
int16u object_layer_height;
if (object_layer_width == 0 ||
object_layer_height == 0 ||
object_layer_width/object_layer_height < 0.1 ||
object_layer_width/object_layer_height > 10)
Здесь целочисленное значение сравнивается с константой '0.1'. Это очень подозрительно. Предположим, что переменные имеют следующие значения:
- object_layer_width = 20;
- object_layer_height = 100;
Программист ожидает, что при делении этих чисел результат будет равен '0.2'. Это подходящее значение, так оно попадает в диапазон [0.1..10].
На самом деле, результат деления будет равен 0. Деление осуществляется над целочисленными типами данных. Потом, при сравнении с '0.1' произойдет расширение до типа 'double', но будет уже поздно. Чтобы исправить код необходимо заранее использовать явное приведение типов:
if (object_layer_width == 0 ||
object_layer_height == 0 ||
(double)object_layer_width/object_layer_height < 0.1 ||
(double)object_layer_width/object_layer_height > 10.0)
Второй пример.
// be_aas_reach.c
ladderface1vertical =
abs( DotProduct( plane1->normal, up ) ) < 0.1;
Аргумент функции abs() имеет тип 'double'. На первый взгляд, код кажется абсолютно правильным и хочется заявить "анализатор здесь сглупил".
Но давайте разберёмся более детально. Давайте посмотрим, как объявлена функция abs() в заголовочных файлах.
int __cdecl abs( int _X);
#ifdef __cplusplus
extern "C++" {
inline long __CRTDECL abs(__in long _X) { .... }
inline double __CRTDECL abs(__in double _X) { .... }
inline float __CRTDECL abs(__in float _X) { .... }
}
#endif
Да, в Си++ функции abs() перегружены для различных типов. Однако, мы имеем дело с кодом на языке Си (файл be_aas_reach.c).
Это значит, что выражение типа 'float' будет неявно преобразовано к типу 'int'. И результат работы функции abs() тоже будет иметь тип 'int'. Значение типа 'int' нет смысла сравнивать с '0.1'. Об этом и предупреждает анализатор.
В программах на языке Си для правильного вычисления модуля потребуется другая стандартная функция:
double __cdecl fabs(__in double _X);
Исправленный код:
ladderface1vertical =
fabs( DotProduct( plane1->normal, up ) ) < 0.1;
Данная диагностика классифицируется как:
|
Взгляните на примеры ошибок, обнаруженных с помощью диагностики V674. |