offsetof
| Определено в заголовочном файле <cstddef>
|
||
#define offsetof(type, member) /* определено реализацией */ |
||
Макрос offsetof заменяется целочисленным константным выражением типа std::size_t, значением которого является смещение в байтах от начала объекта указанного типа до его указанного подобъекта, включая биты заполнения, если таковые имеются.
Учитывая объект o типа type и статическую длительность хранения, o.member должно быть константным выражением lvalue, которое ссылается на подобъект o. Иначе поведение не определено. В частности, если member является статическим элементом данных, битовым полем или функцией-элементом, поведение не определено.
Если type не является PODType (до C++11)типом стандартной компоновки (начиная с C++11), результат offsetof не определён (до C++17)использование макроса offsetof поддерживается условно (начиная с C++17).
Выражение offsetof(type, member) никогда не зависит от типа и зависит от значения тогда и только тогда, когда type зависимый.
Исключения
offsetof не создаёт исключений.
|
Выражение |
(начиная с C++11) |
Примечание
|
Смещение первого элемента типа стандартной компоновки всегда равно нулю (оптимизация пустой базы является обязательным). |
(начиная с C++11) |
offsetof не может быть реализован на стандартном C++ и требует поддержки компилятора: GCC, LLVM.
member не ограничен прямым элементом. Оно может обозначать подобъект данного элемента, например элемент элемента массива. Это указано в C DR 496.
В C23 указано, что определение нового типа в offsetof является неопределённым поведением, и такое использование лишь частично поддерживается некоторыми реализациями в режимах C++: offsetof(struct Foo { int a; }, a) поддерживается ICC и некоторыми старыми версиями GCC, а offsetof(struct Foo { int a, b; }, a) отвергается всеми известными реализациями из-за запятой в определении Foo.
Пример
#include <cstddef>
#include <iostream>
struct S
{
char m0;
double m1;
short m2;
char m3;
// private: int z; // предупреждение: 'S' это нестандартный тип компоновки
};
int main()
{
std::cout
<< "смещение char m0 = " << offsetof(S, m0) << '\n'
<< "смещение double m1 = " << offsetof(S, m1) << '\n'
<< "смещение short m2 = " << offsetof(S, m2) << '\n'
<< "смещение char m3 = " << offsetof(S, m3) << '\n';
}
Возможный вывод:
смещение char m0 = 0
смещение double m1 = 8
смещение short m2 = 16
смещение char m3 = 18
Отчёты о дефектах
Следующие изменения поведения были применены с обратной силой к ранее опубликованным стандартам C++:
| Номер | Применён | Поведение в стандарте | Корректное поведение |
|---|---|---|---|
| CWG 273 | C++98 | offsetof может не работать, если перегружен унарный operator&
|
требуется для правильной работы, даже если operator& перегружен
|
| LWG 306 | C++98 | поведение не было указано, когда type не являлся PODType
|
в этом случае результат не определён |
| LWG 449 | C++98 | другие требования offsetof были удалены решениемLWG проблема 306 |
добавлены обратно |
Смотрите также
| беззнаковый целочисленный тип, возвращаемый оператором sizeof (определение типа) | |
(C++11) |
проверяет, является ли тип типом со стандартной компоновкой (шаблон класса) |
Документация C по offsetof
| |