Я столкнулся с любопытной проблемой с портом javascript моей программы на C (я считаю, что он использует компилятор clang и llvm). Похоже, что доступ к памяти с помощью указателя int*
принудительно выравнивается и приводит к неисправности.
(код в C++
, для интерпретатора BASIC
, и это часть, которая хранит данные в переменной массива)
short offset = getArrayOffset(symbol); // base offset of given BASIC array
// highest (15th) bit of offset is array type flag really
// now we determine array element size (byte or 4-byte int)
char b = (offset & 0x8000) ? 1 : sizeof(numeric);
// multiply size by requested index and add it to get real offset
offset = (offset & 0x7FFF) + b * idx;
// now this offset is added to the pointer of the end of variables area
// and so "p" should point precisely to wanted element
char* p = ((char*)(void*)vars) + sizeof(varHolder) * numVars + offset;
if (b > 1) { // and depending on the element type
*((numeric*)(void*)p) = value; // *** we write "numeric" (i.e. int)
} else {
*((unsigned char*)(void*)p) = (value & 0xFF); // or single byte
}
( ссылка на точную точку в источнике)
Теперь магия такова: varHolder
- это структура из 6 байтов, поэтому, когда у меня есть numVars=1
(определена только переменная этого массива), и выводится разница между vars
и p
, это 6
. Однако целочисленное значение в строке, отмеченной ***
, сохраняется в памяти на два байта ниже!
То же самое с idx=1
- разница между адресами составляет 10
, но значение сохраняется, начиная со смещения 8
.
Более того, если определена другая переменная (таким образом, numVars становится 2
, а разница vars
и p
становится делимой на 4
) - проблема, похоже, исчезает.
Так что мне любопытно узнать, есть ли какое-либо выравнивание по умолчанию для небайтовых указателей. Я еще не смог воспроизвести его с помощью онлайн-компиляторов clang, извините: (
Тем временем хранятся элементы байтового массива (другая ветка if
, кажется, работает отлично).