15

Does this code violate strict aliasing?

struct {int x;} a;
*(int*)&a = 3

More abstractly, is it legal to cast between different types as long as the primitive read/write operations are type correct?

Geoffrey Irving
  • 6,483
  • 4
  • 32
  • 40

1 Answers1

26

First, it is legal to cast in C. §6.7.2.1/13:

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.

The aliasing rule reads as follows (§6.5/7):

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

  • a type compatible with the effective type of the object,
  • a qualified version of a type compatible with the effective type of the object,
  • a type that is the signed or unsigned type corresponding to the effective type of the object,
  • a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
  • 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), or
  • a character type.

Here you would be accessing it via pointers of a "type compatible with the effective type of the object" and "an aggregate or union type that includes one of the aforementioned types among its members", so no problem with aliasing either. So in C, it is indeed perfectly legal to access the first member of a structure by casting the pointer to the structure to the type of the member in question.

In C++, however, you'll often find vtables and other things at the start of a C++ object. In your specific case, however, your structure is of standard layout, and so this is explicitly allowed (§9.2/20 in n3290, thanks Luc Danton! - C++03 apparently has a similar rule, expressed in terms of POD objects).

bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • C++ definitely wouldn't paper over the presence of a vtable, but I'm only applying this in cases with no such weirdness. – Geoffrey Irving Mar 17 '12 at 03:52
  • @Geoffrey : "*cases with no such weirdness*". Aka trivially copyable types? Aka something you should have mentioned in your question? – ildjarn Mar 17 '12 at 03:59
  • 1
    Well, the question mentions that the struct has a single int field, which among other things implies no vtable. The title is already rather verbose. – Geoffrey Irving Mar 17 '12 at 04:12
  • In that specific case it would be a POD type - not sure if the same guarantees apply in C++ though (don't have the spec handy) – bdonlan Mar 17 '12 at 04:29
  • 7
    The relevant rule for C++11 is that a pointer to an object of standard-layout struct type can be `reinterpret_cast` to a pointer to its initial member (9.2 Class members [class.mem] paragraph 20 in n3290). This rule (and anything involving standard-layout types) is designed to mimic the rules of C that are quoted here. C++03 will have similar things except that it will be in terms of POD struct, not standard-layout struct. – Luc Danton Mar 17 '12 at 04:46
  • 1
    You have to prove two different things: (1) the cast is defined, and returns a valid pointer (2) the pointer can be dereferenced, the lvalue can be accessed – curiousguy Jul 21 '12 at 03:11