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
не создаёт исключений.
Выражение noexcept(offsetof(type, member)) всегда оценивается как true. |
(начиная с 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
|