Search code examples
cgccstandardsc99strict-aliasing

Strict aliasing in relation to aggregate or union types


I'm trying to understand the implications of the following statement in the C99 standard (C99; ISO/IEC 9899:1999 6.5/7)

An object shall have its stored value accessed only by an lvalue expression that has one of the following types 73) or 88):

  • (other statements unrelated to question omitted)

  • an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union)

Consider the following:

typedef struct MyComplex {
    float real;
    float imag;
} MyComplex;

MyComplex *carray = malloc(sizeof(*carray) * 10);
float *as_floats = (float *)carray;

Is this legal since the MyComplex structure contains a compatible float type for the as_floats pointer?

What about the other way around? i.e:

float *farray = malloc(sizeof(*farray) * 10);
MyComplex *as_complex = (MyComplex *)farray;

In both cases, ultimately, everything we're dealing with here is a float, so maybe it's ok? I'm just not sure.

I ask, because I'm dealing with a legacy code base that does this kind of stuff all over the place and so far, everything seems fine. But I feel like we're playing with fire here. Trying to figure out if I need to disable strict aliasing on the compiler command line or not.


Solution

  • Note 13 in 6.7.2.1 of (I believe) all versions of the standard condones case #1 explicitly. You'll rarely get a clearer answer! My emphasis

    Within a structure object, the non-bit-field members and the units in which bit-fields reside have addresses that increase in the order in which they are declared. A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning.

    http://port70.net/~nsz/c/c99/n1256.html#6.7.2.1

    YES! You can cast a structure to access its first member directly! Why anyone thinks that's better than &(carray->real) isn't clear. But it's definitely legit.

    As another commenter pointed out I discussed case #2 in a previous question.

    Aliasing Arrays through structs

    It appears in conclusion that case #2 is an OK way to access the member real. Also iff the structure has no internal padding (platform dependent) you could even access the second member of the array through imag.

    I say platform dependent but other investigations have offered no known platform where such a structure would include padding.