# V106. Implicit type conversion N argument of function 'foo' to memsize type.

Анализатор обнаружил потенциально возможную ошибку, связанную с неявным приведением фактического аргумента функции к memsize типу.

Первый пример.

Программа работает с большими массивами, используя контейнер 'CArray' из библиотеки MFC. На 64-битной платформе количество элементов массиве может превысить значение 'INT_MAX' (2Гб), что приведет к неработоспособности следующего кода:

    CArray<int, int> myArray;
    ...
    int invalidIndex = 0;
    INT_PTR validIndex = 0;
    while (validIndex != myArray.GetSize()) {
      myArray.SetAt(invalidIndex, 123);
      ++invalidIndex;
      ++validIndex;
    }

Данный код заполняет все элементы массива 'myArray' значением 123. Он выглядит совершенно корректно, и вы не получите от компилятора никаких предупреждений, несмотря на его неработоспособность на 64-битной архитектуре. Ошибка заключается в использовании в качестве индекса переменной 'invalidIndex' типа 'int'. Когда значение переменной 'invalidIndex' превысит 'INT_MAX', произойдет ее переполнение, и оно получит значение равное "-1". Анализатор диагностирует данную ошибку, предупреждая, что первый аргумент функции 'SetAt' неявно приводится к memsize типу (которым в данном случае является тип 'INT_PTR'). Получив такое предупреждение, вы можете исправить ошибку, изменив тип 'int' на более подходящий.

Данный пример показателен тем, что обвинять программиста в некачественном коде не очень честно. Дело в том, что в старой версии библиотеки MFC функция 'SetAt' в классе 'CArray' была объявлена следующим образом:

    void SetAt(int nIndex, ARG_TYPE newElement);

А в новой:

    void SetAt(INT_PTR nIndex, ARG_TYPE newElement);

Даже разработчики Microsoft, создавая MFC, не смогли учесть все возможные последствия использования типа 'int' для индексации в массиве, и можно простить простого разработчика, написавшего такой код.

Приведем исправленный пример:

    ...
    INT_PTR invalidIndex = 0;
    INT_PTR validIndex = 0;
    while (validIndex != myArray.GetSize()) {
      myArray.SetAt(invalidIndex, 123);
      ++invalidIndex;
      ++validIndex;
    }

Второй пример.

Программа вычисляет необходимый ей размер массива данных, а затем выделяет его с использованием функции 'malloc', как показано ниже:

    unsigned GetArraySize();
    ...
    unsigned size = GetArraySize();
    void *p = malloc(size);

Анализатор выдаст предупреждение на строку "void *p = malloc(size);". Посмотрев определение функции 'malloc', мы увидим, что ее формальный аргумент, задающий размер выделяемой памяти, представлен типом 'size_t'. В программе же в качестве фактического аргумента используется переменная 'size' типа 'unsigned'. Если вашей программе на 64-битной архитектуре понадобится массив более 'UINT_MAX' байт (4Гб), то можно с уверенностью утверждать, что приведенный код неверен, так как тип 'unsigned' не может хранить значение более 'UINT_MAX'. Исправление программы заключается в изменении типов переменных и функций, участвующих в вычислении размера массива данных. В приведенном примере необходимо заменить тип 'unsigned' на один из memsize типов, а также, если это необходимо модифицировать код функции 'GetArraySize'.

    ...
    size_t GetArraySize();
    ...
    size_t size = GetArraySize();
    void *p = malloc(size);

Анализатор выдает предупреждения на неявное приведение типа только в том случае, если оно может привести к ошибке при переносе программы на 64-битную платформу. Ниже приведен код, в котором присутствует неявное приведения типов, но которое не вызывает ошибок:

    void MyFoo(SSIZE_T index);
    ...
    char c = 'z';
    MyFoo(0);
    MyFoo(c);

Если вы точно уверены, что неявное приведение типа фактического аргумента функции совершенно корректно, то для подавления предупреждения анализатора вы можете использовать явное приведение типа, как показано ниже:

    typedef size_t TYear;
    void MyFoo(TYear year);
    int year;
    ...
    MyFoo(static_cast<TYear>(year));

Иногда явное приведение типа может маскировать ошибку. В этом случае вы можете воспользоваться правилом V201.

Дополнительные материалы по данной теме:

- 64-битные уроки. Урок 17. Паттерн 9. Смешанная арифметика.