2016-03-28 8 views
1

私はhttp://en.cppreference.com/w/cpp/language/unionをお読みください。連合ビットフィールド

組合は、その最大のデータメンバを保持するのに必要なだけのように大きいです。他のデータメンバは、その最大メンバの一部と同じバイトに割り当てられます。その割り当ての詳細は実装定義であり、最近作成されたものではないユニオンのメンバーから読み取るための未定義の動作です。

「最近書かれたものではない組合のメンバーから読み込むことは、未定義の動作です」と不思議に思います。

私は、ユニオンが注文ビットを強制するためのパディングを持っているのだろうと思っています。

例:

union { 
uint8_t raw; 
struct { 
    uint8_t a : 1; 
    uint8_t b : 2; 
    uint8_t padding : 5; 
}; 
} U; 

正しくU.rawを読むために大丈夫だろうか?

ありがとうございます。

+0

あなたのコードでは、 ':1'、':2'と ':5'のビットフィールドが重なり合っています。つまり、' padding'は何も埋められません。おそらく、あなたはgoogle "punning C++"とバックグラウンド読んでください。 * "なぜ最近"ではなかった組合のメンバーから読み込むのが未定義なのか不思議です。 "* - ポインタやポインタへの参照のみを使って変数が書き込まれると仮定すると、コンパイラはより積極的に最適化できるためです。同じ型(2つの例外を除いて)。 –

+0

'その割り当ての詳細は実装定義です' - コンパイラは、あなたが格納されているデータを読むことを期待するような方法でコードを最適化することができます。例えば 'b'に格納されたデータ'b'からのみ読み込まれ、' raw'や 'a'では読み込まれません。これは理論的なケースです。また、メモリ内のビットフィールドのレイアウトは標準では指定されていないことに注意してください。 – ubuntugod

+0

@TonyDご返信ありがとうございます。私の例ではバグです。一定。重複はありません。 – Hei

答えて

0

私が使っているgcc x86コンパイラでは、ビットフィールドはLSBからMSBに割り当てられます(下記参照)。 「生の」レイアウトも表示されます。

7       0 
+---+---+---+---+---+---+---+---+ 
|  padding  | b | a | 
+---+---+---+---+---+---+---+---+ 

    7       0 
+---+---+---+---+---+---+---+---+ 
|    raw    | 
+---+---+---+---+---+---+---+---+ 

あなたは8

7       0 
+---+---+---+---+---+---+---+---+ 
|  padding  | b | a | 
+---+---+---+---+---+---+---+---+ 
    0 1 0 0 0 1 0 1 

しかし、その後== 1、B == 2とパディング==(0x45)01000101bする生設定した場合、どのようなMSBからコンパイラ割り当てられたビットフィールドの場合LSBに?

7       0 
+---+---+---+---+---+---+---+---+ 
| a | b |  padding  | 
+---+---+---+---+---+---+---+---+ 

    7       0 
+---+---+---+---+---+---+---+---+ 
|    raw    | 
+---+---+---+---+---+---+---+---+ 

さて、あなたは(0x45)01000101bする生設定した場合、その後== 0、B == 2とパディング== 5.

7       0 
+---+---+---+---+---+---+---+---+ 
| a | b |  padding  | 
+---+---+---+---+---+---+---+---+ 
    0 1 0 0 0 1 0 1 

あなたのコンパイラがレイアウトする方法を理解していればどのようにビットフィールドを割り当てるかについては、これを利用することができますが、これは移植性がないことに注意してください。私は組み込みソフトウェア分野で働いており、私たちはこれを常に利用しています。

+0

ビットのレイアウトが静的でコンパイラ固有で、ユーザーがアクセスするたびに読み書きの両方でレイアウトを変更しようとしないようです。したがって、その場合、U.a、U.b、U.paddingに書き込んだり、U.rawから読み込んだりすると、コンパイラ固有の動作が得られるはずです。標準の "未定義の振る舞い"は、コンパイラの実装者がビットを必要な方法でレイアウトする柔軟性を提供するだけです。私の仮定は正しいのですか? – Hei

+0

正確です。同様に、もしあなたが** float **と** uint32 **の和集合を持っていたら、浮動小数点数(すなわち1.0)を書いてそれをunit32(0x3f800000)として読むことができますが、 floatの低レベルフォーマット。再び、ポータブルではなく、興味深い。 – idmc

0

標準C++では、最も最近書き込まれたものと同じでないユニオンのメンバーにアクセスすると何が起こるかは定義されていません。これはメンバーのタイプやレイアウトとは関係ありません。

プログラムが別のメンバーにアクセスする場合は、コンパイラ固有の拡張機能を使用しています。理論的には、コンパイラはC++でユニオンエイリアシングを定義している場合、その事実を文書化する必要があります。

+0

こんにちは、私はC++標準(バージョンN3337)を読んでいます。あなたが言及した声明がどのセクションにあるのかを指摘できますか?私はそれをもう一度読んで、私が全体の文脈を見逃さないようにしたいと思います。ありがとう! – Hei

+0

N3337は古いバージョンです。 N4140は(ほとんど)最新の公開テキストであり、最新のドラフトテキストは[here](http://eel.is/c++draft/)にあります。セクション[class.union]の最初の文を参照してください。 –

関連する問題