2016-10-26 14 views
7

共通の接頭辞で、標準レイアウト型へのポインタをキャストするのは、私は次のタイプがあるとしましょう:再解釈が

struct Common { int a, b, c; }; 
struct Full { int a, b, c; uint64_t x, y, z; }; 

CommonFullCommonFullの接頭辞である標準レイアウトタイプ、です。私は労働組合の両方を置くのであれば:

union U { 
    Common c; 
    Full f; 
}; 

私はf[class.mem]/23あたりのアクティブメンバーであった場合でも、cを通読して許可されます。

質問があります - 私には、Full const*と与えられた方法は、UB以外の方法でCommon const*を得ることですか?

void foo(Full const* f) { 
    Common c1; 
    memcpy(&c1, f, sizeof(c1)); // this obviously works, but I don't want 
           // to be copying all this stuff 

    auto c2 = reinterpret_cast<Common const*>(f); // is this ok? 
     // c2 and f are pointer-interconvertible iff f comes from a U 
     // but why does that U actually need to exist? 

    auto u = reinterpret_cast<U const*>(f); // ok per basic.lval/8.6?? 
    auto c3 = &u->c;      // ok per class.mem/23?? 
} 
+0

"pointer-interconvertible"はオブジェクトのプロパティであり、型ではありません。共用体がない場合、 'reinterpret_cast'の結果は依然として' * f'を指しています。 –

+0

@ T.C。ええ、無関係なタイプの無関係なオブジェクトを要求するのはちょっと奇妙ではありませんか? – Barry

+0

これはC互換性のためだけに存在する型システムの例外です。 P0137R0がすべてを完全に禁止したことを思い出してください。 –

答えて

0

短い答え:オブジェクトアドレスを別のクラスにキャストし直し、ポインタを介してアクセスすることは未定義の動作です。

理由は、コンパイラでより簡単なエイリアス解析を可能にするためだと思います。 コンパイラは、タイプXのオブジェクトが関連のないタイプYのオブジェクトにエイリアスできないと仮定できる場合、レイアウト互換性がある場合でも、そうしないと実行できない最適化を実行できる場合があります。

struct X 
{ 
    int a; 
    int b; 
}; 

struct Y 
{ 
    int c; 
    int d; 
}; 

void updateXY(X *x, Y* y) 
{ 
    x->a = y->c; 
    x->b = y->c; // if *x and *y could alias, y->c would have to be reloaded 
} 

void updateXX(X *x, X* xx) 
{ 
    x->a = xx->a; 
    x->b = xx->a; // the compiler must reload xx->a because x and xx may alias 
} 

gccとclangはエイリアスを考慮しているため、実際にはupdateXYをupdateXX以上に最適化します。

updateXY(X*, Y*): 
    mov eax, DWORD PTR [rsi] // cache y->c 
    mov DWORD PTR [rdi], eax 
    mov DWORD PTR [rdi+4], eax 
    ret 
updateXX(X*, X*): 
    mov eax, DWORD PTR [rsi] 
    mov DWORD PTR [rdi], eax 
    mov eax, DWORD PTR [rsi] // reload y->c 
    mov DWORD PTR [rdi+4], eax 
    ret 

すなわち、最適化に関係なく行われ、XY間の労働組合は、コンパイラに表示されているかどうかエイリアス解析のための違いを確認していないようです。実際には、非アクティブな共用体メンバへのポインタを渡したコードはまだ破損している可能性があります。 constポインターを渡すのあなたのusecaseのためにこれは無関係であるべきです。