In &(X(a, s))
, &
применяется к ((struct S*)(a, &s : 0))
. Тип этого выражения struct S*
, и это значение (значение указателя на struct S
). &
не может применяться к значению, которое не является lvalue. 1
In &(X(a, s)->x)
, &
применяется к ((struct S*)(a, &s : 0))->x
. Это выражение берет указатель на struct S
и использует его для ссылки на член x
, который является int
. Это lvalue, потому что он обозначает объект int
, который является членом x
(C 2018 6.5.2.3 4 явно говорит, что результат ->
является lvalue). Поскольку это lvalue, к нему можно применить &
.
Сноска
1 Согласно C 2018 6.5.3.2 1, оператор адреса &
должен быть применен к обозначению функции, результат [ ]
или унарный *
, или lvalue, который обозначает объект, который не является битовым полем и не объявлен с register
.