Я смотрю на макрос offsetof
от <cstddef>
и увидел, что возможная реализация через
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
Я попробовал, и это действительно работает, как ожидалось
#include <iostream>
#define my_offsetof(type, member) ((void*) &(((type*)nullptr)->member))
struct S
{
char x;
short y;
int z;
};
int main()
{
std::cout << my_offsetof(S, x) << '\n';
std::cout << my_offsetof(S, y) << '\n';
std::cout << my_offsetof(S, z) << '\n';
S s;
std::cout << (void*) &((&s)->x) << '\n'; // no more relative offsets
std::cout << (void*) &((&s)->y) << '\n'; // no more relative offsets
std::cout << (void*) &((&s)->z) << '\n'; // no more relative offsets
}
единственная модификация, которую я сделал, это то, что я использую окончательный актерский состав void*
вместо size_t
, так как я хочу отобразить адрес в виде указателя.
Мои вопросы):
nullptr
тогда взять его адрес? Если это так, то кажется, что &(((type*)nullptr)->member)
вычисляет адрес члена относительно 0, действительно ли это так? (кажется, так как в последних 3 строках я получаю смещения относительно адреса s
). (void*)
из определения макроса я получаю сегфо. Зачем? не должны &(((type*)nullptr)->member)
быть указателем типа type*
, или тип как-то здесь стирается?
- Код совершенно законен?
Нет. Это неопределенное поведение. Компилятор может решить реализовать offsetof
таким образом, но это потому, что это является реализация: он может выбирать, как реализовать свои собственные функции. Вы, с другой стороны, не получаете такой «роскоши».
У вас нет возможности реализовать offsetof
макро. Не в соответствии со стандартами.
- Если я удаляю окончательное приведение к (void *) из определения макроса, я получаю segfault. Зачем? не должны &(((type *) nullptr) -> member) быть указателем типа type *, или тип как-то здесь удален?
Вероятно, это ошибка из-за попытки печати my_offsetof(S, x)
(поскольку x
это char
и это выражение приводит к char*
), так как std::ostream
«s operator<<
постараюсь напечатать char*
как строка в стиле C.
Других решений пока нет …