In C, a.b
is normally synonymous with (&a)->b
.
Is this true in absolutely all cases, even if a
is a macro for some messy compound term? Or are there any edge cases, in any version of C, in which the equivalence fails to hold?
In C, a.b
is normally synonymous with (&a)->b
.
Is this true in absolutely all cases, even if a
is a macro for some messy compound term? Or are there any edge cases, in any version of C, in which the equivalence fails to hold?
Here are three counterexamples, all based on constraints on applying &
:
a
is an rvalue because it is a structure returned by a function:
int bar(void)
{
extern struct S { int b; } foo(void);
return (&foo())->b;
}
Clang says “error: cannot take the address of an rvalue of type 'struct S'”. But it accepts return foo().b;
.a
is an rvalue because it is the result of an assignment:
int bar(void)
{
struct S { int b; } x = {0};
struct S y;
return (&(y=x))->b;
}
Clang says “error: cannot take the address of an rvalue of type 'struct S'”. But it accepts return (y=x).b;
.a
is declared with register
, so its address may not be taken:
int bar(void)
{
register struct S { int b; } a = {0};
return (&a)->b;
}
Clang says “error: address of register variable requested”.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.
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.