V674. The 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;

Согласно Common Weakness Enumeration, потенциальные ошибки, найденные с помощью этой диагностики, классифицируются как CWE-682.

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V674.


Найденные ошибки

Проверено проектов
344
Собрано ошибок
12 970

А ты совершаешь ошибки в коде?

Проверь с помощью
PVS-Studio

Статический анализ
кода для C, C++, C#
и Java

goto PVS-Studio;