5 ms·
First, this is not undefined, so you are going to need to find another example :) 6.7.2.1/13 "Within a structure object, the non-bit-field members and the uni
by DannyBee 10y ago
First, this is not undefined, so you are going to need to find another example :)
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."
(This is also known as the first member rule)
6.5/7 then says:
"
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."
These are both types compatible with the effective type of the object.
IE your first pointer is really also an int*, as is your second pointer. Your dereference attempt, which is an access to an int, through something with an effective type of pointer to an int, is a valid thing to do.
(Note: I implemented a large part of of GCC's current pointer aliasing analysis and rules, though the underlying TBAA set construction predates me by quite a while :P)
Now, if you added a field and tried this with the second member, of a different type than the first, you'd maybe get a different answer.
However, pay close attention to:
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
GCC takes this very seriously. So if you construct types that contain both compatible types, and use that, gcc will consider it okay, no matter how weird what you are doing is.
(Note also i do not claim either set of rules produces sane results, and in fact, can easily construct examples where the standard says nonsensical things, or rules seem to change depending on whether you have one source file or two or ...)
In general, however, your complaint is basically: "C is not a pure structural type system, it's a name based one for the most part". This is true, and it is meant to be that way.
There are other programming languages with structural type systems (OCaml is a good example).
- pascal_cuoq 10y ago> First, this is not undefined, so you are going to need to find another example :) This example will do just fine, in fact. It is arguably not undefined, as you say. It is also silently miscompiled by both Clang and GCC. https://godbolt.org/g/7Gb9S3 https://godbolt.org/g/7Gb9S3 And there you have one of the problems with type-based aliasing optimizations: the people who write compilers have not read the standard and just make it up as they are going along. They have been acting like the six-year-old who pretends to be reading rules from the back of the box in a game of Monopoly.
- DannyBee 10y agoYou should file a bug report. This should in fact, work, and did, in fact, work, when i stopped working on it. If you split the type definitions across different translation units, it will stop working (because it can't know they are compatible), but this is one of the weird edge cases. "And there you have one of the problems with type-based aliasing optimizations: the people who write compilers have not read the standard and just make it up as they are going along. They have been acting like the six-year-old who pretends to be reading rules from the back of the box in a game of Monopoly. " This is, well, bullshit. The situations get incredibly complex very quickly, and it's completely unclear in a lot of cases what the standard meant to happen. You should not assume bad faith without a good reason. The vast majority of people implementing this stuff either are committee members, or work closely with them, so saying "they haven't read the standard" just makes you look petty, because, in a lot of cases, they helped write the standard. At the same time, while implementing it, i think we filed something like 15 DR's against the standard, some of which are still unresolved because the committee didn't know what to do and punted on it due to lack of consensus. So if you want to say who makes it up as they go along, i think you may be pointing fingers in the wrong direction: Take, for example, DR 236 which was filed in 2000, and was not resolved until 2006, and they basically punted (note how the answer does not answer the questions): http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_236.htm http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_236.htm (note also that most DR's from the same time period were resolved in 1 year or less) GCC had at least 3 committee members who were consulted on most of this stuff, and agreed with the current set of interpretations. In short, if you think it's so easy to do, feel free to fix it. I think you will find yourself quickly in a world of trying to figure out what anyone meant to happen. Contrary to what you seem to think, there are rarely objectively right answers, just interpretations that you can get consensus or no consensus for. (Not sure what one would expect from a programming language standard built by something akin to the UN)