Урок 14. Паттерн 6. Изменение типа массива

24.01.2012

Иногда в программах необходимо (или просто удобно) представлять элементы массива в виде элементов другого типа. Опасное и безопасное приведение типов представлено в следующем коде:

int array[4] = { 1, 2, 3, 4 };
enum ENumbers { ZERO, ONE, TWO, THREE, FOUR };
//safe cast (for MSVC)
ENumbers *enumPtr = (ENumbers *)(array);
cout << enumPtr[1] << " ";
//unsafe cast
size_t *sizetPtr = (size_t *)(array);
cout << sizetPtr[1] << endl;
//Output on 32-bit system: 2 2
//Output on 64-bit system: 2 17179869187

Как видите, результат вывода программы отличается в 32-битном и 64-битном варианте. На 32-битной системе доступ к элементам массива осуществляется корректно, так как размеры типов size_t и int совпадают, и мы видим вывод "2 2".

На 64-битной системе мы получили в выводе "2 17179869187", так как именно значение 17179869187 находится в 1-ом элементе массива sizetPtr (см. рисунок 1). В некоторых случаях именно такое поведение и бывает нужно, но обычно это является ошибкой.

Примечание. Тип enum в компиляторе Visual C++ по умолчанию совпадает размером с типом int, то есть является 32-битным типом. Использование enum другого размера возможно только с помощью расширения, считающимся нестандартным Visual C++. Поэтому приведенный пример корректен в Visual C++, но с точки зрения других компиляторов приведение указателя на элементы int к указателю на элементы enum может быть также некорректным.

Picture 1004543

Рисунок 1 - Расположение элементов массивов в памяти

Исправление описанной ситуации заключается в отказе от опасных приведений типов путем модернизации программы. Другим вариантом является создание нового массива и копирование в него значений из исходного массива.

В основном описанный паттерн ошибки встречается в коде, где в качестве уникальных 32-битных идентификаторов пытаются использовать значения указателей.

Диагностика

Опасные изменения типа массива диагностируются инструментом PVS-Studio. Анализатор предупреждает о потенциально опасных приведениях типа с помощью диагностических сообщений V114. Соответственно, выводятся предупреждения только о тех конструкциях, которые могут привести к ошибке на 64-битной системе. Например, следующий код является корректным и анализатор не обратит на него внимание программиста:

void **pointersArray;
ptrdiff_t correctID = ((ptrdiff_t *)pointersArray)[index];

Авторы курса: Андрей Карпов (karpov@viva64.com), Евгений Рыжков (evg@viva64.com).

Правообладателем курса "Уроки разработки 64-битных приложений на языке Си/Си++" является ООО "Системы программной верификации". Компания занимается разработкой программного обеспечения в области анализа исходного кода программ. Сайт компании: http://www.viva64.com.

Контактная информация: e-mail: support@viva64.com, 300027, г. Тула, а/я 1800.