Что делает следующий макрос?

в исходном коде qemu у меня есть следующий макрос с именем offsetof. Кто-нибудь может сказать мне, что он делает?

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *) 0)->MEMBER)

Он используется таким образом:

offsetof(CPUState, icount_decr.u32)

где CPUState — это структура.

Я думаю, что это дает смещение члена внутри структуры, но я не уверен.

РЕДАКТИРОВАТЬ: Да, я узнал, что происходит. В определении CPUState был макрос, который я пропустил, который включал переменную icount_decr.


person apoorv020    schedule 10.08.2010    source источник
comment
en.wikipedia.org/wiki/Offsetof   -  person Matt Davis    schedule 11.08.2010
comment
Макрос технически вызывает неопределенное поведение, но работает во многих местах. Современный (например, GCC 4) <stddef.h> определит его во встроенном компиляторе, чтобы избежать неопределенности, а также некоторых головных болей C++.   -  person zwol    schedule 11.08.2010
comment
@Zack: Как я уже сказал в ответе, это библиотечная функция, так что нет, это не неопределенное поведение. Реализация может реализовать ее так, как они хотят. (По сути, эта конкретная реализация требует, чтобы адрес разыменованного нулевого указателя был четко определен для конкретного компилятора.)   -  person GManNickG    schedule 11.08.2010
comment
Система может реализовать это так, как она хочет. Однако он говорит, что это находится в исходном коде qemu, где поведение было бы неопределенным. Хотя вполне вероятно, что это действительно сработает.   -  person jcoder    schedule 11.08.2010


Ответы (3)


Он получает смещение члена структуры. Это делается путем приведения нулевого адреса к структуре этого типа, а затем получения адреса члена.

person Amardeep AC9MF    schedule 10.08.2010
comment
Компиляторы C/C++ в последнее время добавляют для этого встроенную функцию, главным образом потому, что вы можете сломать эту технику с помощью перегруженных операторов в C++, а также потому, что это является технически неопределенным поведением, и вы можете представить себе достаточно агрессивные точки -к оптимизации ломая его. - person zwol; 11.08.2010
comment
@Zack: это функция библиотеки, так что нет, это не неопределенное поведение. Реализация может реализовать ее так, как они хотят. - person GManNickG; 11.08.2010
comment
Он подразумевает, что этот макрос определен внутри прикладной программы, и в этом случае его поведение является неопределенным (хотя, конечно, весьма вероятно, что оно будет работать так, как ожидалось). Если бы определение было в стандартной библиотеке, то оно, конечно, не было бы неопределенным. - person jcoder; 11.08.2010
comment
@John: Если offsetof действительно (пере) определено какой-либо библиотекой, они сделали программу неправильной, используя зарезервированный идентификатор. Они должны использовать тот, который определен в стандартной библиотеке. - person GManNickG; 11.08.2010
comment
Я собираюсь быть невероятно щепетильным и настаивать на том, что ((size_t) &((TYPE *) 0)->MEMBER) на самом деле всегда вызывает поведение, не определенное стандартом C, независимо от того, где оно появляется. Теперь, если он появляется как расширение макроса <stddef.h> определенного компилятора C offsetof, тогда эта реализация определяет его для вычисления значения, которое должен вычислить offsetof. Но приложение, безусловно, не должно предполагать, что оно знает, как определить offsetof. Дальнейшее разделение: offsetof является зарезервированным идентификатором только в том случае, если <stddef.h> был включен (в C; C++ немного отличается). - person zwol; 11.08.2010
comment
@Zack: Надеюсь, вы видите, что я не понял, что макрос переопределяется вне стандартной библиотеки. И справедливо, хотя я сомневаюсь, что что-то могло бы зайти очень далеко, если бы в конечном итоге не было включено stddef.h. - person GManNickG; 11.08.2010
comment
Да, я видел; Мне просто захотелось сделать микрофибры ;-) К ​​вашему сведению, в C стандартные заголовки должны вести себя так, как если бы они не включали друг друга, так что вы можете продвинуться довольно далеко, не поднимая stddef.h. (Вот что я имел в виду, когда сказал, что C++ немного отличается. Я бы распаковал его, но у меня закончились символы.) - person zwol; 11.08.2010
comment
Я предполагаю, что есть законный смысл, скрывающийся в расщеплении волос. Библиотека C - это просто больше C (и, как правило, некоторая сборка) - если ваш компилятор имеет оптимизацию, которая нарушает ((size_t) &((TYPE *)0)->MEMBER), он не будет узнавать, исходит ли это из официального определения offsetof в stddef. h, или от кого-то, играющего в глупых педерастов. - person zwol; 11.08.2010

Ваше мышление правильное! И название макроса тоже дает хороший намек. ;)

person Dmitry Brant    schedule 10.08.2010

Это определено в §7.17/3:

offsetof(type, member-designator)
, которое расширяется до целочисленного константного выражения типа size_t, значением которого является смещение в байтах к элементу структуры (обозначенному обозначением-членом) от начала его структура (обозначается по типу). Обозначение типа и члена должно быть таким, чтобы при заданном
static type t;
выражение &(t.member-designator) оценивалось как адресная константа. (Если указанный элемент является битовым полем, поведение не определено.)

Поскольку библиотека не обязательно должна следовать языковым правилам, реализация может получить результат, какой ей заблагорассудится.

Таким образом, результатом этой конкретной реализации является не неопределенное поведение, потому что предполагается, что вам все равно, как оно реализовано. (Другими словами, ваша реализация гарантирует, что получение адреса косвенного обращения через нулевой указатель будет четко определено. Вы, конечно, не можете предполагать это в своих собственных программах.)

Если какая-то библиотека (пере)определила offsetof, они сделали поведение вашей программы неопределенным и вместо этого должны использовать стандартную библиотеку. (Макетики.)

person GManNickG    schedule 10.08.2010