V206. Explicit conversion from 'void *' to 'int *'.


Предупреждение информирует о наличии явного приведения типа 'void *', 'byte *' к указателю на функцию или к указателю на 32/64-битные целочисленные типы данных. Или наоборот.

Конечно, само по себе такое приведение типа не является ошибкой. Давайте разберёмся для чего реализована такая диагностика.

Достаточно часто указатель на какой-то буфер памяти передаются в другую часть программы с помощью указателя на байт или void. Причины написать такой код могут быть различны. Часто это свидетельствует о плохом дизайне, но этот вопрос выходит за рамки документации. Указатели на функцию тоже часто хранятся как void *.

Итак, в каком-то месте программы указатель на массив/функцию сохраняется как void *, а в другом происходит обратное приведение типа. При портировании, такой код чреват ошибками. В одном месте, тип данных может быть изменён, а в другом нет.

Рассмотрим пример:

size_t array[20];
void *v = array;
....
unsigned* sizes = (unsigned*)(v);

Этот код корректно работает в 32-битном режиме, так как размеры типов 'unsigned' и 'size_t' совпадают. В 64-битном режиме, размер типов отличается и поведение программы начнет отличаться от ожидаемого. См. также: паттерн 6 - изменение типа массива.

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

unsigned array[20];
void *v = array;
....
unsigned* sizes = (unsigned*)(v);

Или так:

size_t array[20];
void *v = array;
....
size_t* sizes = (size_t*)(v);

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

void Do(void *ptr, unsigned a)
{
  typedef void (*PtrFoo)(DWORD);
  PtrFoo f = (PtrFoo)(ptr);
  f(a);
}

void Foo(DWORD_PTR a) { /*... */ }

void Call()
{
  Do(Foo, 1);
}

Исправленный вариант кода:

typedef void (*PtrFoo)(DWORD_PTR);

Примечание. Анализатор знает о множестве случаев, когда явное приведение типа безопасно. Например, он не обращает внимание, на явное приведение указателя типа void *, который вернула функция malloc():

int *p = (int *)malloc(sizeof(int) * N);

Как было отмечено в начале, явное приведение типа само по себе не является ошибкой. Поэтому не смотря на большое количество исключений из правила, анализатор всё равно генерирует много ложных предупреждений V206. Анализатор не знает, есть ли в программе другие места, где неправильно используются эти указатели. Поэтому он выдаёт предупреждения на все потенциально опасные приведения типов.

Например, выше были приведены два примера некорректного кода и способы их исправления. Но анализатор, будет продолжать выдавать предупреждения и на уже исправленный код.

Можно предложить следующий способ работы с этим предупреждением. Вы один раз внимательно просматриваете все сообщения V206 после чего отключаете эту диагностику в настройках. Если ложных предупреждений не много, то можно воспользоваться один из методов подавления ложных предупреждений.


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

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

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

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

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

goto PVS-Studio;