问题
offsetof
is defined like this in stddef.h
:
#define offsetof(type, member) ((size_t)&((type *)0)->member)
Does this invoke undefined behavior due to the dereference of a NULL pointer? If not, why?
回答1:
In normal C code, the behavior of ((size_t)&((type *)0)->member)
is not specified by the C standard:
- First, per C 2018 6.5.2.3 4, about
->
,((type *)0)->member
designates the lvalue of the membermember
of the structure to which(type *)0
points. But((type *)0)
does not point to a structure, and therefore there is no member this can be the lvalue of. - Supposing it does give an lvalue for some hypothetical structure, there is no guarantee that taking its address and converting it to
size_t
yields the offset of the member, both because we do not know that(type *)0
yields an address that is actually represented with zero in the implementation’s addressing scheme and because the conversion of a pointer to an integer specified by C 2018 6.3.2.3 6 only tells us the result is implementation-defined, not that it yields the address in any otherwise meaningful form.
Were this code in a standard header, such as <stddef.h>
, it is under the control of the C implementation and not the C standard, and so questions about whether it is undefined according to the C standard do not apply. The C standard only says how the standard headers behave when included—an implementation may use any means it chooses to achieve the required effects, whether that is simply defining the behavior of source code that is not fully defined by the C standard or putting source code in an entirely different language in the headers. (In fact, the file stddef.h could be entirely empty or not exist at all, and the compiler could supply its required declarations when it sees #include <stddef.h>
without reading any actual file from disk.)
回答2:
Leaving aside all the other reasons why it might not be a correct implementation of offsetof
,
#define offsetof(type, member) ((size_t)&((type *)0)->member)
is not appropriate even as part of the implementation because everything in stddef.h
must work correctly in both C and C++, and in C++, the above construct definitely will misbehave in the presence of overloaded operator->
. This is why GCC's stddef.h
switched to using a special intrinsic function called __builtin_offsetof
upwards of fifteen years ago.
Yes, I am saying that if you saw this in some stddef.h
, that stddef.h
is buggy.
来源:https://stackoverflow.com/questions/57342141/does-this-implementation-of-offsetof-invoke-undefined-behavior