# 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;

Данная диагностика классифицируется как:

CWE-682 CERT-FLP36-C

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