Как часть функции инициализатора памяти, я хочу проверить, что необработанный буфер, полученный в аргументе, имеет правильное выравнивание, которого требует контракт.
Инициализатор предназначен для получения произвольного указателя памяти и создания экземпляра структуры на месте при условии соблюдения ограничений по размеру и выравниванию. Возвращает указатель на целевой тип.
Поскольку целевая структура объявлена, предполагается, что можно получить ограничение выравнивания. Это можно сделать с помощью alignof()
(на C11) или offsetof()
или с комбинацией sizeof()
. См. этот предыдущий SO ответ по теме. Я протестировал все варианты, все они дают одинаковый результат.
Моя текущая проблема выглядит следующим образом:
поскольку целевая структура содержит несколько полей long long
, ее выравнивание, как ожидается, составит 8 байт в системах x64 и 4 байта в системах x86 (32-разрядных). Это уже известно: несмотря на то, что поля long long
имеют длину 8 байт, 32-разрядные процессоры просто эмулируют 64-разрядные операции с кучей 32-разрядных, так что значение составляет всего 4 байта.
Если я проверяю ограничение выравнивания структуры, используя любой из вышеупомянутых методов, я получаю 8 на x64. На 32-битном x86 gcc
и clang
дают 4, тогда как Visual по-прежнему возвращает 8 .
ОК, первое удивление, я ожидал, что все компиляторы будут использовать одинаковые ограничения выравнивания и правила заполнения для данного ABI, и здесь Visual отличается. Но это становится более странным.
Давайте теперь предположим, что целевая структура размещена непосредственно в стеке, используя ее публичное объявление, а затем передадим адрес выделенной структуры в качестве аргумента функции инициализатора.
Теперь, используя Visual для 32-битной x86, инициализация завершается ошибкой половину времени, потому что структура фактически выровнена по границе 4 байта, а проверка возвращает 8 (это возвращаемое значение alignof()
).
Это кажется странным. Я что-то пропустил или наблюдаю ошибку Visual?