>
>
>
V106. Implicit type conversion N argume…


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.

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