Code sample:
struct name
{
int a, b;
};
int main()
{
&(((struct name *)NULL)->b);
}
Does this cause undefined behaviour? We could debate whether it "dereferences null", however C11 doesn't define the term "dereference".
6.5.3.2/4 clearly says that using *
on a null pointer causes undefined behaviour; however it doesn't say the same for ->
and also it does not define a -> b
as being (*a).b
; it has separate definitions for each operator.
The semantics of ->
in 6.5.2.3/4 says:
A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue.
However, NULL
does not point to an object, so the second sentence seems underspecified.
Also relevant might be 6.5.3.2/1:
Constraints:
The operand of the unary
&
operator shall be either a function designator, the result of a[]
or unary*
operator, or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.
However I feel that the bolded text is defective and should read lvalue that potentially designates an object , as per 6.3.2.1/1 (definition of lvalue) -- C99 messed up the definition of lvalue, so C11 had to rewrite it and perhaps this section got missed.
6.3.2.1/1 does say:
An lvalue is an expression (with an object type other than void) that potentially designates an object; if an lvalue does not designate an object when it is evaluated, the behavior is undefined
however the &
operator does evaluate its operand. (It doesn't access the stored value but that is different).
This long chain of reasoning seems to suggest that the code causes UB however it is fairly tenuous and it's not clear to me what the writers of the Standard intended. If in fact they intended anything, rather than leaving it up to us to debate :)
offsetof
. – Unbiased&E
is a valid pointer expression (where & is the ‘‘address-of ’’ operator, which generates a pointer to its operand), the expression(&E)->MOS
is the same asE.MOS
." I think this covers the relationship between.
and->
. – Autogamya->b
is maybe not as separate from(*a).b
as you assume. – Autogamy(&(((struct name *)NULL)->b))->b
is the same as(((struct name *)NULL)->b)->b
. This note only applies whenE
has a struct type, but hereE
is anint
– Pew->
operator and an identifier" does not designate a member of a structure object. Hence,((struct name *)NULL)->b
violates semantics of the->
operator. – Lauree