Is it legal to index into a struct?

It is illegal 1. That’s an Undefined behavior in C++.

You are taking the members in an array fashion, but here is what the C++ standard says (emphasis mine):

[dcl.array/1]: …An object of array type contains a contiguously allocated non-empty set of N
subobjects of type T…

But, for members, there’s no such contiguous requirement:

[class.mem/17]: …;Implementation alignment requirements might cause two adjacent
members not to be allocated immediately after each other

While the above two quotes should be enough to hint why indexing into a struct as you did isn’t a defined behavior by the C++ standard, let’s pick one example: look at the expression (&thing.a)[2] – Regarding the subscript operator:

[expr.post//expr.sub/1]:
A postfix expression followed by an expression in square brackets is a
postfix expression. One of the expressions shall be a glvalue of type
“array of T” or a prvalue of type “pointer to T” and the other shall
be a prvalue of unscoped enumeration or integral type. The result is
of type “T”. The type “T” shall be a completely-defined object type.66
The expression E1[E2] is identical (by definition) to ((E1)+(E2))

Digging into the bold text of the above quote: regarding adding an integral type to a pointer type (note the emphasis here)..

[expr.add/4]: When an expression that has integral type is added to or subtracted from a
pointer, the result has the type of the pointer operand. If the
expression P points to element x[i] of an array object x
with n elements, the expressions P + J and J + P (where J has
the value j) point to the (possibly-hypothetical) element x[i + j]
if 0 ≤ i + j ≤ n; otherwise, the behavior is undefined. …

Note the array requirement for the if clause; else the otherwise in the above quote. The expression (&thing.a)[2] obviously doesn’t qualify for the if clause; Hence, Undefined Behavior.


On a side note: Though I have extensively experimented the code and its variations on various compilers and they don’t introduce any padding here, (it works); from a maintenance view, the code is extremely fragile. you should still assert that the implementation allocated the members contiguously before doing this. And stay in-bounds :-). But its still Undefined behavior….

Some viable workarounds (with defined behavior) have been provided by other answers.



As rightly pointed out in the comments, [basic.lval/8], which was in my previous edit doesn’t apply. Thanks @2501 and @M.M.

1: See @Barry’s answer to this question for the only one legal case where you can access thing.a member of the struct via this parttern.

Leave a Comment