Search code examples
cstrict-aliasing

Can two structs in C99/C11 alias?


Suppose we have two structs

struct hello {  
  float a;
  float b;
};

and

struct world {
  float c;
  float d;
};

and a function

void func(struct hello* h, struct world* w);

Is it the case that the two arguments can alias, as they both contain float and therefore the compiler must generate a code that ensures correctness? If I am certain that w and h are not stored in the same memory location (or do not overlap in any way), would I achieve speed-up by changing the function to the following?

void func(struct hello *restrict h, struct world *restrict w);

Moreover, does the primitive type of float have any effect on this or do the same rules apply to an int?


Solution

  • Your example is very close to creating two structs that are of compatible type (C11 6.2.7). But in order to be compatible, they must have the same members with the same names, and the struct tags must also be the same.

    You don't have that, so (TL;DR) the structs in the question cannot alias.

    Another thing one can play around with however, is a trick called common initial sequence (C11 6.5.2.3) where you can put both structs inside a union, which is visible in the translation unit. You'd then be allowed to inspect the first sequence of members of each struct type, until the point where they stop being compatible. You could do this:

    typedef union
    {
      struct hello h;
      struct world w;
    } hack_t;
    

    Then access individual members of either struct. Unfortunately, this rule is a bit exotic and compilers don't always support it well apparently - the rule was subject to some Defect Reports (DR). I'm not certain of its status in current C17.

    But regardless of that trick, the union still makes it possible to lvalue access a struct hello or a struct world through a hack_t, since it is a union type that includes a compatible type among its members (C11 6.5/7). Mildly useful I suppose.

    Apart from those cases, you cannot wildly cast pointer types from one pointer type to the other and de-reference. It would be a strict aliasing violation (C11 6.5/7) even if all individual members are compatible types. (You can however of course access any individual float member by de-referencing a float pointer to that member.)

    Your restrict optimization does not apply since the structs can't alias, unless they are truly compatible types. So the compiler will assume they are always in different memory regions.

    It doesn't matter if you use float or any other primitive data type, they all behave the same with the exception of the character types. A pointer to a character type can be used to access any data without strict aliasing violation (but not the other way around, reading character type through another incompatible type).