Is a.b always (&a)->b?
In C,
a.b
is normally synonymous with(&a)->b
.
There is nothing in the C11
standard that mandates this equivalence under all circumstances. The relevant section (5.5.2.3 Structure and union members
) actually deals with them distinctly and the footnote in that section indicates where the misapprehension arises:
If
&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
.
In other words, &E
has to be valid for this equivalence to hold. One place where it doesn't hold is:
#include <stdio.h>
struct xyzzy { int plugh; } twisty;
struct xyzzy getTwistyCopy(void) { return twisty; }
int main(void) {
twisty.plugh = 42;
printf("%d\n", ( getTwistyCopy() ).plugh);
printf("%d\n", ( &(getTwistyCopy()) )->plugh);
}
The first printf
line is fine but the second is not. That's really because you cannot take the address of a function return value. But you can still see, for an arbitrary a
, that a.b
and (&a)->b
are not always identical.
Here are three counterexamples, all based on constraints on applying &
:
a
is an rvalue because it is a structure returned by a function:
Clang says “error: cannot take the address of an rvalue of type 'struct S'”. But it acceptsint bar(void) { extern struct S { int b; } foo(void); return (&foo())->b; }
return foo().b;
.a
is an rvalue because it is the result of an assignment:
Clang says “error: cannot take the address of an rvalue of type 'struct S'”. But it acceptsint bar(void) { struct S { int b; } x = {0}; struct S y; return (&(y=x))->b; }
return (y=x).b;
.a
is declared withregister
, so its address may not be taken:
Clang says “error: address of register variable requested”.int bar(void) { register struct S { int b; } a = {0}; return (&a)->b; }
In a.b
, a
is not required to be an lvalue.
For example, if a
is a macro that expands to a function call, then (&a)->b
is a constraint violation.