Получение смещения переменной-члена посредством приведения nullptr

Я смотрю на макрос 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, так как я хочу отобразить адрес в виде указателя.

Мои вопросы):

  1. Является ли код полностью законным, то есть законно ли «доступ» к члену через nullptrтогда взять его адрес? Если это так, то кажется, что &(((type*)nullptr)->member) вычисляет адрес члена относительно 0, действительно ли это так? (кажется, так как в последних 3 строках я получаю смещения относительно адреса s).
  2. Если я уберу окончательный акт (void*) из определения макроса я получаю сегфо. Зачем? не должны &(((type*)nullptr)->member) быть указателем типа type*, или тип как-то здесь стирается?

2

Решение

  1. Код совершенно законен?

Нет. Это неопределенное поведение. Компилятор может решить реализовать offsetof таким образом, но это потому, что это является реализация: он может выбирать, как реализовать свои собственные функции. Вы, с другой стороны, не получаете такой «роскоши».

У вас нет возможности реализовать offsetof макро. Не в соответствии со стандартами.

  1. Если я удаляю окончательное приведение к (void *) из определения макроса, я получаю segfault. Зачем? не должны &(((type *) nullptr) -> member) быть указателем типа type *, или тип как-то здесь удален?

Вероятно, это ошибка из-за попытки печати my_offsetof(S, x) (поскольку x это char и это выражение приводит к char*), так как std::ostream«s operator<< постараюсь напечатать char* как строка в стиле C.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]