C++ reinterpret_cast целое число

Я наткнулся на следующий код C++:

 #define OFFSETOF_MEMBER(t, f) \
  (reinterpret_cast<uintptr_t>(&reinterpret_cast<t*>(16)->f) - static_cast<uintptr_t>(16u)) // NOLINT

где t это тип, f это имя поля. Интересно, почему мы можем поставить целое число 16 в качестве параметра reinterpret_cast.

3 ответа

16 - это адрес, который мы назначаем указателю, который позволяет нам вычислить смещение указанного члена. Адрес указателя - просто число, поэтому мы можем злоупотреблять этим фактом, чтобы получить информацию о наших структурах / классах.

Скажем, у нас есть структура:

struct point { 
    //Assuming 32-bit integer sizes. 
    //For 64-bit integersizes, 0x0, 0x8, 0x10 for the integer offsets
    int x; //Offset 0x0
    int y; //Offset 0x4
    int z; //Offset 0x8
}; static_assert(sizeof(point) == 12 /* or 0xC in hex */);

Мы используем макрос:

OFFSETOF_MEMBER(point, y);

Развернув макрос, мы получим:

(reinterpret_cast<uintptr_t>(&reinterpret_cast<point*>(16)->y) - static_cast<uintptr_t>(16u)

Еще один способ выразить reinterpret_cast<point*>(16)->y можно было бы так: point * myPt = 16u; мы знаем, что 16 не является допустимым адресом, но компилятор этого не делает, и пока мы не пытаемся прочитать адрес, на который мы указываем, все в порядке.

Далее мы можем упростить все &reinterpret_cast<point*>(16)->y чтобы: &myPt->y, Сверху мы знаем, что y равно @ offset 0x4, а myPt равно 16: 16 + 0x4 = 20

Тогда у нас есть reinterpret_cast<uintptr_t>(20u) - static_cast<uintptr_t(16u) или же 20 - 16, что дает нам смещение у, то есть 0x4.

Целое число 16 - это просто адрес памяти. выражение reinterpret_cast<t*>(16) просто означает "интерпретировать объект по адресу 16 как тип t", но вы знаете, что нет такого t объект по адресу. Теоретически, 16 может быть заменено любым 4x (32-битным) или 8x (64-битным) целым числом. Если вы выбираете 0Макрос может быть упрощен как:

#define OFFSETOF_MEMBER(t, f) \
  (reinterpret_cast<uintptr_t>(&reinterpret_cast<t*>(0)->f))

См. Offsetof для получения дополнительной информации.

Из ссылки:

3) Значение любого целочисленного типа или типа перечисления может быть преобразовано в тип указателя. [...]

Так, reinterpret_cast<> частично разработан, чтобы сделать именно это.

Другие вопросы по тегам