2016-07-13 3 views
0

との奇妙な行動I持って次のスニペットC++:reinterpret_castは

#include <iostream> 

using namespace std; 

class foobar 
{ 
    public: 
    unsigned int a = 97; 
    unsigned int b = 98; 
    unsigned int c = 99; 
}; 


class barfoo 
{ 
    public: 
    char a:32,b:32,c; 

}; 


int main(){ 
    foobar * f = new foobar(); 
    barfoo * b = (reinterpret_cast<barfoo *>(f)); 
    cout << b->a << "-" << b->b << "-" << b->c; 

} 

出力:私はbarfooにおけるCの幅を指定した場合

a-b-c 

しかし、それは動作しません(すべての値は0です)。守って

#include <iostream> 

using namespace std; 

class foobar 
{ 
    public: 
    unsigned int a = 97; 
    unsigned int b = 98; 
    unsigned int c = 99; 
}; 


class barfoo 
{ 
    public: 
    char a:32,b:32,c:32; 

}; 


int main(){ 
    foobar * f = new foobar(); 
    barfoo * b = (reinterpret_cast<barfoo *>(f)); 
    cout << b->a << "-" << b->b << "-" << b->c; 

} 

出力:

-- 

文字はすべてこれが起こっている理由を0

任意のアイデアですか? second snippetをideoneする

リンケの作業 - - first snippetをideoneする

リンク

コンパイラを動作していないが、GCC-5.1 感謝です!

+1

'char a:32'は32ビットを保持できますか?また、私はUBを使用する際にあまりにも一貫性があるとは思わないでしょう。 –

+5

あなたがやっていることは未定義の行動と呼ばれています。したがって、この場合、 'reinterpret_cast'の動作は正しいです。あなたのプログラムをクラッシュさせても正しい動作になります。ハードドライブのフォーマットは正しい動作です。悪魔をあなたの鼻から飛ばすことは正しい行動です。何も保証されていません。 –

+0

@πάνταῥεῖまあ、それはコンパイルされ、出力が正しいように見えます。したがって、私は「はい」と言う傾向があります。さらに、charが解析されるとき、それはまだわずか8ビットです、これはフィールドを整列させることです。 – Kariem

答えて

2

まず、2つのクラスが同じサイズであるかどうかを確認します。おそらく、パディングとアライメントによって、ビットフィールドa、b、cの位置が、通常のメンバーa、b、cの位置と異なる場合があります。なぜ、32ビットビットフィールドにcharを使用していますか?私のコンパイラは、型の大きさを超えるビットフィールドについて警告します。

それ以外の場合(barfooクラスのcharをunsigned intに変更した場合)、スローされたstandardese-UBに関係なく、reinterpret_castとaccessは動作する可能性があります。多分あなたがよくサポートされ、よく確立されたタイプ・ペニングのイディオムを組合に使っていれば、もっともっとそうかもしれません。

ユニオンを介した型打ちは、コンパイラーに、別のタイプの2つのポインターがエイリアスであり、エイリアスではないと仮定して過激な最適化を行わないように指示する方法です。

4

それの結果の割り当てが許容される一方でbのいずれかのその後のアクセスは未定義の動作であるので、これreinterpret_castは、定義された動作のための要件を満たしていない:

barfoo * b = (reinterpret_cast<barfoo *>(f)); 

reinterpret_castところ、これらの条件のいずれかを満たす必要があります。 foobarはDynamicTypeあり、barfooはAliasedTypeある:

  • AliasedTypeである(おそらくCV-qualifie D)DynamicType
  • AliasedTypeとDynamicType共に(おそらくはCV修飾各レベル)
  • AliasedTypeは同じ型Tへのポインタ可能性マルチレベル、(おそらくCV修飾)が署名またはDynamicType
  • の符号なしバリアント
  • AliasedTypeは、前述の型の1つを要素または非静的メンバ(再帰的に、含まれている共用体の部分集約要素および非静的データメンバの要素を含む)として保持する集約型または共用体型です。これは安全ですその非静的なメンバまたは要素へのポインタを与えられた構造体または共用体へのポインタを取得する。
  • AliasedType DynamicType
  • の(おそらくはCV修飾)基底クラスである
  • AliasedTypeはchar又はunsigned charである:これはunsigned char型の配列として任意のオブジェクトのオブジェクト表現の検査を可能にします。

AliasedTypeがこれらの条件のいずれにも該当しないのでreinterpret_castの結果へのアクセスは未定義の動作です。

+2

私は同意しません。 'reinterpret_cast'自体は未定義の振る舞いではありません。実際にリンクしたページには、' f'と同じポインタを得るために 'reinterpret_cast''を' b'に戻すことができなければならないと述べられています。それは、逆参照が定義されていない振る舞いであることだけを示しています。 – skyking

+0

@skykingあなたは100%正しいです。私が直接リンクしているページには、「キャストは常に成功しますが、結果のポインタまたは参照は、次のいずれかが当てはまる場合にオブジェクトにアクセスするためにのみ使用できます。私は編集しました。ダウン投票と退会ではなく、読んでコメントする時間をとっていただきありがとうございます。あなたは私の答えに特に恵まれ、一般的にはhttp://stackoverflow.comです! –

+0

最初の行はまだ間違っています(または少なくとも混乱しています)。 – skyking