Вам не хватает состава, чтобы сделать эту работу. Вам необходимо привести к байтовому типу, прежде чем вычесть смещение, а затем восстановить обратно до bar*
. Причина в том, что макрос offsetof
возвращает смещение в виде количества байтов. Когда вы делаете указатель арифметики c, вычитание и сложение работают в терминах размера указанного типа. Давайте сделаем пример:
Давайте предположим, что у вас есть экземпляр bar
с именем b
, который находится по адресу 0x100h. Предполагая, что sizeof(double) == 8
, sizeof(int) == 4
и sizeof(float) == 4
, тогда sizeof(bar) == 16
и ваша структура и ее члены будут выглядеть в памяти так:
b @ 0x100h
b.a @ 0x100h
b.b @ 0x108h
b.c @ 0x10Ch
offsetof(bar,b)
будет равно 8
, Ваш исходный код говорит: «обрабатывайте 0x108h так, как будто он указывает на структуру типа bar
. затем дайте мне структуру bar
по адресу 0x108h - 8 * sizeof(bar)
или, в частности: 0x108h - 0x80h = 88h. ' Надеемся, что пример демонстрирует, почему исходный код выполнял неправильные вычисления.
Вот почему вам нужно указать компилятору, что вы хотите вместо этого вычитать адреса в байтах, чтобы получить правильный адрес первого члена в вашей структуре.
Решение будет выглядеть что-то вроде этого:
bar* owner = reinterpret_cast<bar*>(reinterpret_cast<char *>(i) - offsetof(bar, b));
Одна вещь, к которой вы должны быть очень осторожны: это le git , только если bar
равно стандартная компоновка . Вы можете использовать шаблон std::is_standard_layout<bar>::value
, чтобы сделать утверждение c, чтобы убедиться, что вы случайно не вызываете UB.