2012-02-01

waqur: (Default)
Был проект, в котором некие высокоуровневые классы парсили и генерили низкоуровневые структуры для сериализации и выгрузки на диск — обычное дело. Это были POD-типы, точнее структуры с завершающим элементом типа "массив произвольного размера". Как-то так:
struct MyPodType
{
    uint32_t  foo;
    uint32_t  bar;
    ...
    uint16_t  last_field_array[];
};


В ходе рефакторинга кода в этих структурах решено было заменить встроенные типы на классы, которые учитывают порядок следования байт (uint32_le например). Мало ли, вдруг под BigEndian собираться когда-нибудь будем. Все такие вещи надо делать правильно (tm).
struct MyPodType
{
    uint32_le  foo;
    uint32_le  bar;
    ...
    uint16_le  last_field_array[];
};


uint32_le — это C++ный класс, который инкапсулирует всякие байтсвопы и прочее платформеннозависимое говно с глаз долой и обеспечивает неявную конверсию в uint32_t (но не при конструировании). Равенство его размера uint32 статически ассертируется при компиляции, рядом с объявлением класса настраиваются аттрибуты для правильного выравнивания, в общем вся эта кухня работает давно и успешно.

Возвращаемся к нашим баранам.

Код, который работал с POD-структурами, частенько после считывания чего-нибудь с диска, проверял, "а достаточно ли у нас данных?". Проверял вот так:
if( loaded_data_size < offsetof(MyPodType, last_field_array) )
    Мяу();

Далее шло вычисление точного размера структуры, включая хвост, на основе данных в фиксированной части структуры, и ещё одна такая проверка, но в данном контексте это неважно.

А важно то, что после замены uint32_t на uint32_le структурки перестали соответствовать критерию "POD" и следовательно компилятор перестал хавать offsetof. Вернее, MSVC хавает, а GCC на той же кодовой базе говорит:
invalid access to non-static data member 'MyPodType::last_field_array' of NULL object
(perhaps the 'offsetof' macro was used incorrectly)


Попытки перейти на __builtin_offsetof, отказаться от него, выписать свой макрос явно, например
((std::size_t)(&((type *)0)->field))
или
(((unsigned char*)(&((type *)0)->field)) - ((unsigned char*)0))
или
(((unsigned char*)(&((type *)0x1000)->field)) - ((unsigned char*)0x1000))
или
(((std::size_t)(&((type *)0x1000)->field)) - 0x1000)
а также заменить в коде offsetof(MyPodType, last_field_array) на offsetof(MyPodType, last_field_array[0])
ни к чему не привели — то же самое сообщение компилятора.

Проблема гораздо глужбе, а именно — вавка в голове у составителей стандарта:
http://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-non-pod-strucutures-in-c
Microsoft по старой доброй традиции *уи клал на все стандарты и на всех их составителей, включая комитеты, подкомитеты и целевые рабочие группы ISO в полном составе, но гнусятники в этом смысле решили повыпендриваться и проявить комсомольско-павликморозовский энтузиазм.

Что думает вельмишановное панство (помимо очевидного
g++ -Wno-invalid-offsetof
) ?

March 2024

S M T W T F S
     12
3456789
10111213141516
17181920212223
24252627282930
31      

На этой странице

Автор стиля

Развернуть

No cut tags
Page generated 2025-09-07 03:47 pm
Powered by Dreamwidth Studios