jcoder jcoder - 17 days ago 7
C Question

Is it legal to index into a struct?

Regardless of how 'bad' the code is, and assuming that alignment etc are not an issue on the compiler/platform, is this undefined or broken behavior?

If I have a struct like this :-

struct data
{
int a, b, c;
};

struct data thing;


Is it legal to access
a
,
b
and
c
as
(&thing.a)[0]
,
(&thing.a)[1]
, and
(&thing.a)[2]
?

In every case, on every compiler and platform I tried it on, with every setting I tried it 'worked'. I'm just worried that the compiler might not realize that b and thing[1] are the same thing and stores to 'b' might be put in a register and thing[1] reads the wrong value from memory (for example). In every case I tried it did the right thing though. (I realize of course that doesn't prove much)

This is not my code; it's code I have to work with, I'm interested in whether this is bad code or broken code as the different affects my priorities for changing it a great deal :)

Tagged C and C++ . I'm mostly interested in C++ but also C if it is different, just for interest.

Answer

It is not legal. That's an undefined behavior.

There are many things that may happen in ways that will break your code. For example, the compiler is permitted to pad members of a struct. And if that happens in your code, you are toasted. Period.

The C++ standard says:

[basic.lval/8]

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:

-- the dynamic type of the object,

-- a cv-qualified version of the dynamic type of the object,

-- a type similar (as defined in [conv.qual]) to the dynamic type of the object,

-- a type that is the signed or unsigned type corresponding to the dynamic type of the object,

-- a type that is the signed or unsigned type corresponding to a cv-qualified version of the dynamic type of the object,

-- an aggregate or union type that includes one of the aforementioned types among its elements or non-static data members (including, recursively, an element or non-static data member of a subaggregate or contained union),

-- a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,

-- a char or unsigned char type.

Regarding the padding:

[class.mem/24]: If a standard-layout class object has any non-static data members, its address is the same as the address of its first non-static data member. Otherwise, its address is the same as the address of its first base class subobject (if any). [ Note: There might therefore be unnamed padding within a standard-layout struct object, but not at its beginning, as necessary to achieve appropriate alignment. — end note ] [ Note: The object and its first subobject are pointer-interconvertible ([basic.compound], [expr.static.cast]). — end note ]

Comments