C99 strict aliasing rules in C++ (GCC)
By : user1967534
Date : March 29 2020, 07:55 AM
To fix this issue No, you are probably mixing different things. Strict aliasing rules have absolutely nothing to do with C99 standard specifically. Strict aliasing rules are rooted in parts of the standard that were present in C and C++ since the beginning of [standardized] times. The clause that prohibits accessing object of one type through a lvalue of another type is present in C89/90 (6.3) as well as in C++98 (3.10/15). That's what strict aliasing is all about, no more, no less. It is just that not all compilers wanted (or dared) to enforce it or rely on it. Both C and C++ languages are sometimes used as "high-level assembly" languages and strict aliasing rules often interfere with such uses. It was GCC that made that bold move and decided to start relying on strict aliasing rules in optimizations, often drawing complaints from those "assembly" types. code :
int *pi;
...
double *pd = static_cast<double *>(static_cast<void *>(pi));
|
Placement-new vs gcc 4.4.3 strict-aliasing rules
By : vmenck
Date : March 29 2020, 07:55 AM
fixed the issue. Will look into that further OK, you can do it if you are willing to store an extra void *. I reformatted your sample a bit so it was easier for me to work with. Look at this and see if it fits your needs. Also, note that I provided a few samples so you can add some templates to it that will help usability. They can be extended much more, but that should give you a good idea. There is also some output stuff to help you see what is going on. code :
#include <new>
#include <iostream>
class Duck
{
public:
Duck(float s = 0.0f, bool q = false) : _speed(s), _quacking(q)
{
std::cout << "Duck::Duck()" << std::endl;
}
virtual ~Duck() // virtual only to demonstrate that this may not be a POD type
{
std::cout << "Duck::~Duck()" << std::endl;
}
float _speed;
bool _quacking;
};
class Soup
{
public:
Soup(int s = 0, float t = 0.0f) : _size(s), _temperature(t)
{
std::cout << "Soup::Soup()" << std::endl;
}
virtual ~Soup() // virtual only to demonstrate that this may not be a POD type
{
std::cout << "Soup::~Soup()" << std::endl;
}
int _size;
float _temperature;
};
enum TypeEnum {
TYPE_UNSET = 0,
TYPE_DUCK,
TYPE_SOUP
};
template < class T > TypeEnum type_enum_for();
template < > TypeEnum type_enum_for< Duck >() { return TYPE_DUCK; }
template < > TypeEnum type_enum_for< Soup >() { return TYPE_SOUP; }
/** Tagged-union style variant class, can hold either one Duck or one Soup, but not both at once. */
class DuckOrSoup
{
public:
DuckOrSoup() : _type(TYPE_UNSET), _data_ptr(_data) {/* empty*/}
~DuckOrSoup() {Unset();}
void Unset() {ChangeType(TYPE_UNSET);}
void SetValueDuck(const Duck & duck)
{
ChangeType(TYPE_DUCK);
reinterpret_cast<Duck*>(_data_ptr)[0] = duck;
}
void SetValueSoup(const Soup & soup)
{
ChangeType(TYPE_SOUP);
reinterpret_cast<Soup*>(_data_ptr)[0] = soup;
}
template < class T >
void set(T const & t)
{
ChangeType(type_enum_for< T >());
reinterpret_cast< T * >(_data_ptr)[0] = t;
}
template < class T >
T & get()
{
ChangeType(type_enum_for< T >());
return reinterpret_cast< T * >(_data_ptr)[0];
}
template < class T >
T const & get_const()
{
ChangeType(type_enum_for< T >());
return reinterpret_cast< T const * >(_data_ptr)[0];
}
private:
void ChangeType(int newType);
template <int S1, int S2> struct _maxx {enum {sz = (S1>S2)?S1:S2};};
#define compile_time_max(a,b) (_maxx< (a), (b) >::sz)
enum {STORAGE_SIZE = compile_time_max(sizeof(Duck), sizeof(Soup))};
char _data[STORAGE_SIZE];
int _type; // a TYPE_* indicating what type of data we currently hold
void * _data_ptr;
};
void DuckOrSoup :: ChangeType(int newType)
{
if (newType != _type)
{
switch(_type)
{
case TYPE_DUCK: (reinterpret_cast<Duck*>(_data_ptr))->~Duck(); break;
case TYPE_SOUP: (reinterpret_cast<Soup*>(_data_ptr))->~Soup(); break;
}
_type = newType;
switch(_type)
{
case TYPE_DUCK: (void) new (_data) Duck(); break;
case TYPE_SOUP: (void) new (_data) Soup(); break;
}
}
}
int main(int argc, char ** argv)
{
Duck sample_duck; sample_duck._speed = 23.23;
Soup sample_soup; sample_soup._temperature = 98.6;
std::cout << "Just saw sample constructors" << std::endl;
{
DuckOrSoup dos;
std::cout << "Setting to Duck" << std::endl;
dos.SetValueDuck(sample_duck);
std::cout << "Setting to Soup" << std::endl;
dos.SetValueSoup(sample_soup);
std::cout << "Should see DuckOrSoup destruct which will dtor a Soup"
<< std::endl;
}
{
std::cout << "Do it again with the templates" << std::endl;
DuckOrSoup dos;
std::cout << "Setting to Duck" << std::endl;
dos.set(sample_duck);
std::cout << "duck speed: " << dos.get_const<Duck>()._speed << std::endl;
std::cout << "Setting to Soup" << std::endl;
dos.set(sample_soup);
std::cout << "soup temp: " << dos.get_const<Soup>()._temperature << std::endl;
std::cout << "Should see DuckOrSoup destruct which will dtor a Soup"
<< std::endl;
}
{
std::cout << "Do it again with only template get" << std::endl;
DuckOrSoup dos;
std::cout << "Setting to Duck" << std::endl;
dos.get<Duck>() = Duck(42.42);
std::cout << "duck speed: " << dos.get_const<Duck>()._speed << std::endl;
std::cout << "Setting to Soup" << std::endl;
dos.get<Soup>() = Soup(0, 32);
std::cout << "soup temp: " << dos.get_const<Soup>()._temperature << std::endl;
std::cout << "Should see DuckOrSoup destruct which will dtor a Soup"
<< std::endl;
}
std::cout << "Get ready to see sample destructors" << std::endl;
return 0;
}
|
Am I breaking strict aliasing rules?
By : Bobby Jatahwa
Date : March 29 2020, 07:55 AM
I wish this helpful for you There is only one intrinsic that "extracts" the lower order double value from xmm register: code :
double _mm_cvtsd_f64 (__m128d a)
return _mm_cvtsd_f64(x);
|
Dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
By : egglee
Date : March 29 2020, 07:55 AM
it fixes the issue You are not allowed to interpret an object trough an incompatible pointer as you do: code :
*(uint32_t*) hash;
uint32_t* p = ( uint32_t* )hash ; //cast must be there, pointer p is not valid
uint32_t u = *p ; //dereference the pointer, this is undefined behaviour
#include <stdint.h>
#include <limits.h>
uint8_t h[] = { 3 , 2 , 1 , 0 } ; //1*3 + 256*2 + 65536*1 + 16777216 * 0
uint32_t a = 0 ;
for( size_t i = 0 ; i < sizeof( a ) ; i++ )
{
a = a | ( h[i] << ( CHAR_BIT*i ) ) ;
}
printf("%u" , a ) ; //66051
|
warning! dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
By : Leonardo Cavazzani
Date : March 29 2020, 07:55 AM
Any of those help You should use something like the following to don't break strict aliasing rule:
|