dereferencing type-punned pointer will break strict-aliasing

dereferencing type-punned pointer will break strict-aliasing の警告を回避する方法.

C/C++では,以下のようなType-punned pointerを使うコードは,厳密には動作が保証できない.

   float f = 123;
   uint32_t u = *(uint32_t*)&f;

このようなコードは,例えば GCCで "-O3 -Wall"のようなオプションを付けてコンパイルすると

dereferencing type-punned pointer will break strict-aliasing 

という警告が出る.理由は,以下のURLあたりが詳しい.

で,肝心の解決方法は, union を使って以下のように書きなおすのが良いらしい.

typedef union {
    float f;
    uint32_t u;
} union32_t;
#define POINTER_TO_UINT32(p) (((union32_t*)(p))->u)
#define POINTER_TO_FLOAT32(p) (((union32_t*)(p))->f)

 float f=123;
 uint32_t u = POINTER_TO_UINT32(&f);

このunionを使う方法は移植性が高いらしく, ffmpeg ライブラリの実装等で時々目にする.

なお別解としては,char*に一度キャストする方法

   float f=123;
   char *tmp = &f;
   uint32_t u = *(uint32_t*)tmp;

memcpyしちゃう方法

   float f=123;
   uint32_t u;
   memcpy(&u, &f, sizeof(u));

がある.

さらにGCC限定であれば,

  • 変数の属性に __attribute__( (may_alias ) ) を付ける方法
  • GCCのオプションに-fno-strict-aliasing を付ける方法

もある.