We just upgraded our compiler to gcc 4.6 and now we get some of these warnings. At the moment our codebase is not in a state to be compiled with c++0x and anyway, we don't want to run this in prod (at least not yet) - so I needed a fix to remove this warning.
The warnings occur typically because of something like this:
struct SomeDataPage
{
// members
char vData[SOME_SIZE];
};
later, this is used in the following way
SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor
To read, update and return for example, the following cast used to happen
reinterpret_cast<SomeType*>(page.vData)->some_member();
This was okay with 4.4; in 4.6 the above generates:
warning: type punned pointer will break strict-aliasing rules
Now a clean way to remove this error is to use a union
, however like I said, we can't use c++0x (and hence unrestricted unions), so I've employed the horrible hack below - now the warning has gone away, but am I likely to invoke nasal daemons?
static_cast<SomeType*>(reinterpret_cast<void*>(page.vData))->some_member();
This appears to work okay (see simple example here: http://www.ideone.com/9p3MS) and generates no warnings, is this okay(not in the stylistic sense) to use this till c++0x?
NOTE: I don't want to use -fno-strict-aliasing
generally...
EDIT: It seems I was mistaken, the same warning is there on 4.4, I guess we only picked this up recently with the change (it was always unlikely to be a compiler issue), the question still stands though.
EDIT: further investigation yielded some interesting information, it seems that doing the cast and calling the member function in one line is what is causing the warning, if the code is split into two lines as follows
SomeType* ptr = reinterpret_cast<SomeType*>(page.vData);
ptr->some_method();
this actually does not generate a warning. As a result, my simple example on ideone is flawed and more importantly my hack above does not fix the warning, the only way to fix it is to split the function call from the cast - then the cast can be left as a reinterpret_cast
.
SomeDataPage page;
new(page.vData) SomeType(); // non-trivial constructor
reinterpret_cast<SomeType*>(page.vData)->some_member();
This was okay with 4.4; in 4.6 the above generates:
warning: type punned pointer will break strict-aliasing rules
You can try:
SomeDataPage page;
SomeType *data = new(page.vData) SomeType(); // non-trivial constructor
data->some_member();
Why not use:
SomeType *item = new (page.vData) SomeType();
and then:
item->some_member ();
I don't think a union is the best way, it may also be problematic. From the gcc docs:
`-fstrict-aliasing'
Allows the compiler to assume the strictest aliasing rules
applicable to the language being compiled. For C (and C++), this
activates optimizations based on the type of expressions. In
particular, an object of one type is assumed never to reside at
the same address as an object of a different type, unless the
types are almost the same. For example, an `unsigned int' can
alias an `int', but not a `void*' or a `double'. A character type
may alias any other type.
Pay special attention to code like this:
union a_union {
int i;
double d;
};
int f() {
a_union t;
t.d = 3.0;
return t.i;
}
The practice of reading from a different union member than the one
most recently written to (called "type-punning") is common. Even
with `-fstrict-aliasing', type-punning is allowed, provided the
memory is accessed through the union type. So, the code above
will work as expected. However, this code might not:
int f() {
a_union t;
int* ip;
t.d = 3.0;
ip = &t.i;
return *ip;
}
How this relates to your problem is tricky to determine. I guess the compiler is not seeing the data in SomeType
as the same as the data in vData
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With