Ian Lance Taylor <[EMAIL PROTECTED]> writes: > Sergei Organov <[EMAIL PROTECTED]> writes: > >> Below are two example functions foo() and boo(), that I think both are >> valid from the POV of strict aliasing rules. GCC 4.2 either warns about >> both (with -Wstrict-aliasing=2) or doesn't warn about any (with >> -Wstrict-aliasing), and generates the assembly as if the functions don't >> violate the rules, i.e, both functions return 10. > > -Wstrict-aliasing=2 is documented to return false positives. Actually > both current versions of -Wstrict-aliasing are pretty bad.
Well, they are indeed bad, but on the other hand I fail to see how to make them pretty without analyzing the entire source of a program, and even then the "effective type of an object" could change at run-time :( Overall, I tend to refrain from blaming gcc too much for weakness of these warnings. >> $ cat alias.c >> typedef struct { int i; } S; >> >> int i; >> int foo() >> { >> S const sc = { 10 }; >> i = 20; >> // Accessing object 'i' of type 'int' through 'S' containing 'int' >> // field. Should be OK from C99 standard POV? >> *(S*)&i = sc; > > C99 says that you can access an object via "an aggregate or union type > that includes one of the aforementioned [basically, compatible] types > among its members (including, recursively, a member of a subaggregate > or contained union)" (section 6.5, paragraph 7). So on that basis > this looks OK to me. Yes, it looked OK due to that rule to me too, until I just came up with the following example in which either I've finally violated some rule, or GCC miscompiles the code: $cat alias3.c typedef struct { int i; float f; } H0; typedef struct { float f; int i; } H1; H1 h1 = { 0, 10 }; int float_as_int() __attribute__((noinline)); int float_as_int() { h1.f = 1; H0 h0 = *(H0*)&h1.f; // Should be OK? No, it is not?! return h0.i; } #include <stdio.h> int main() { printf("%#x\n", float_as_int()); printf("%#x\n", float_as_int()); } $ gcc-4.1 -W -Wstrict-aliasing -O3 alias3.c -o alias3 $ ./alias3 0 0x3f800000 $ Any comments? > >> S s; >> int boo() >> { >> s.i = 20; >> // Accessing 's' of type 'S' through 'int'. Is it aliasing rules >> // violation? Maybe yes, but on the other hand this could be >> // considered as accessing 's.i' of type 'int' through 'int' that >> // should be OK from C99 standard POV? >> *(int*)&s = 10; >> return s.i; >> } > > I think this should also be OK. > > The main point is that you are accessing the object with the correct > type (int). Yes, I hoped it is so, my doubt was that C99 defines "effective type" of an object to be "its declared type", and "declared type" of object 's' is obviously 'S' in this example, but from the standard itself it was not entirely clear for me that an address in memory could have multiple effective types associated with it at the same time. > The use of the struct wrapper does not change that. If > you used a struct for which the type of the field was not the same as > the type of the variable, then this usage would be an aliasing > violation. These are good news. In fact this particular function arose from a doubt if it's possible to achieve C++-alike inheritance in C99 and still write aliasing-clean code when accessing "derived" object through a pointer to its "base" type. Now my next doubt will be if it's possible to implement free() in C99 as there seems to be no way to "forget" the effective object type of a dynamically allocated object. ;) > > It is possible that somebody else will disagree with me. Hopefully not, and thank you very much for the answers. -- Sergei.