struct m
{
int parent:3;
int child:3;
int mother:2;
};
void main()
{
struct m son={2,-6,5};
printf("%d %d %d",son.parent,son.child,son.mother);
}
プログラムの出力がなぜであるかを教えてください2 2 1
。
表示されているフィールドの重要なビットを除くすべてを取り出します。
parent: 3 bits (1-sign bit + 2 more), value 010, result 2
child: 3 bits (1-sign bit + 2 more), value 010, result 2
mother: 2 bits (1 sign bit + 1 more), value 01, result 1
詳細
int
構造体フィールドがビットフィールド値として宣言されていることを指摘する必要があります。C99-§6.7.2,2 により、次の型はすべて同等です: int
、signed
、またはsigned int
。したがって、構造体フィールドはsignedです。C99-§6.2.6.2,2 により、変数の「符号」(負または正) を表すためにビットの 1 つが消費されるものとします。さらに、同じセクションは、符号ビットを除いて、残りのビット表現は関連する符号なしに対応しなければならないと述べています残りのビット数の型。C99-§6.7.2,1 は、これらの各ビットが 2 の累乗を表す方法を明確に定義しています。したがって、通常、符号ビットとして使用される唯一のビットは最上位ビットです (残っている唯一のビットですが、これが標準の不正確な解釈であるかどうかは、いずれわかると確信しています)。サンプルに使用されるテスト値の 1 つとして負の数を割り当てているということは、これを認識している可能性があることを示唆していますが、ビット フィールドに新たにさらされた多くの人々はそうではありません。したがって、それは注目に値します。
C99 標準の次のセクションは、この回答の残りの部分で参照されています。最初はさまざまなタイプへのプロモーションを扱い、次は評価と潜在的な価値の変化 (もしあれば) を扱います。最後は、ビットフィールドのint
型がどのように決定されるかを理解する上で重要です。
C99-§6.3.1.1: ブール値、文字、および整数
2:
int
が元の型のすべての値を表すことができる場合 (ビットフィールドの幅によって制限されるため)、値はint
;に変換されます。それ以外の場合は、に変換されますunsigned int
。これらは整数プロモーションと呼ばれます。他のすべての型は、整数の昇格によって変更されません。C99-§6.3.1.3 符号付きおよび符号なし整数
- 整数型の値が _Bool 以外の別の整数型に変換される場合、その値が新しい型で表現できる場合、その値は変更されません。
- それ以外の場合、新しい型が符号なしの場合、値が新しい型の範囲内になるまで、新しい型で表現できる最大値よりも 1 多い値を繰り返し加算または減算することによって、値が変換されます。
- それ以外の場合、新しい型は署名され、値を表現できません。結果が実装定義であるか、実装定義のシグナルが発生します。
C99-§6.7.2.1 構造体と共用体の指定子
10:ビットフィールドは、指定されたビット数で構成される符号付きまたは符号なしの整数型を持つものとして解釈されます。値 0 または 1 が _Bool 型の非ゼロ幅ビット フィールドに格納される場合、ビット フィールドの値は格納された値と等しくなります。_Bool ビット フィールドには、_Bool のセマンティクスがあります。
int
テスト値の通常のビット表現を検討してください。以下は 32 ビットint
実装です。
value : s bits
2 : 0 0000000 00000000 00000000 00000010 <== note bottom three bits
-6 : 1 1111111 11111111 11111111 11111010 <== note bottom three bits
5 : 0 0000000 00000000 00000000 00000101 <== note bottom two bits
上記の標準参照の要件を適用して、これらのそれぞれについて説明します。
int parent:3
:最初のフィールドは 3 ビットの符号付きint
で、10 進数の値が割り当てられています2
。右辺int
値型 は左辺値型 を包含していint:3
ますか? はい、タイプは良いです。値 2
は左辺値型の範囲内に収まるか? まあ、2
簡単に に収まるint:3
ので、値をいじる必要もありません。最初のフィールドは正常に機能します。
int child:3
: 2 番目のフィールドも 3 ビットの符号付きint
で、今回は 10 進数値が割り当てられています-6
。繰り返しになりますが、右辺値型 ( int
) は左辺値型 ( ) を完全に包含していint:3
ますか? はい、タイプは問題ありません。ただし、符号付きの値を表すために必要な最小ビット数は4ビットです。( )、符号ビットとして最上位ビットを説明します。したがって、値は 3 ビットの符号付きビット フィールドの許容ストレージの範囲外です。したがって、結果は§6.3.1.3-3 に従って実装定義されます。-6
1010
-6
int mother:2
最後のフィールドは 2 ビットの signedint
で、今回は 10 進数の値 5 が割り当てられます。ここでも、右辺値の型 ( int
) は左辺値の型 ( ) を完全に包含していint:2
ますか? はい、タイプは問題ありません。ただし、ここでも、ターゲット タイプに収まらない値に直面しています。符号付き正を表すために必要な最小ビット数5
は 4 (0101) です。一緒に仕事をするのは2人だけです。したがって、結果は再び§6.3.1.3-3 に従って実装定義されます。
したがって、これを正しく理解すれば、この場合の実装は、宣言されたビット深度を埋めるために必要なビットを除いて、すべてをハッキングするだけです。そして、そのハッキングの結果が、あなたが今持っているものです。2 2 1
ノート
プロモーションの順序を間違って反転させた可能性は十分にあります (私は失読症であり、定期的に頭の中で物事を反転させるため、標準で迷子になりがちです)。その場合は、標準のより強い解釈を持っている人にこれを指摘してください。それに応じて回答します。
child
およびのビット フィールドのサイズmother
が小さすぎて、割り当てている定数値を格納できず、オーバーフローしています。
コンパイル段階で次の警告が表示されることに注意してください。
test.c: In function ‘main’:
test.c:18:11: warning: overflow in implicit constant conversion
test.c:18:11: warning: overflow in implicit constant conversion
これは、変数を int 全体ではなく int の 3 ビットとして定義したためです。オーバー フローとは、値を 3 ビット メモリに格納できないことを意味します。
したがって、次の構造定義を使用すると、コンパイルで警告が回避され、正しい値が得られます。
struct m
{
int parent;
int child;
int mother;
};
child
保持するには最低4ビットが必要です-6
(1010
)。またmother
、保持するには最低4ビットが必要です5
(0101
)。
printf
child
その印刷の最後の3ビットのみを考慮し、その印刷2
の最後の2ビットのみを考慮します。mother
1
child
保存には3ビットしか必要ないと思うかもしれません-6
が、実際には符号ビットを含めて4ビットが必要です。負の値は、2の補数モードで格納されるために使用されます。
Binary equivalent of 6 is 110
one`s complement of 6 is 001
two`s complement of 6 is 010
sign bit should be added at MSB.
したがって、の値は-6
です1010
。printf
符号ビットを省略しています。
-6 を 3 ビットだけで表現することはできません。同様に、5 を 2 ビットだけで表すことはできません。
parent
、child
、およびmother
がビット フィールドである必要 がある理由はありますか?
まず第一に:
5
は101
2 進数なので、2 ビットには収まりません。
-6
また、3ビットには収まりません。
ビット フィールドが小さすぎます。また、これは単なる演習ですか、それとも (時期尚早に) 最適化しようとしていますか? 結果に満足することはできません...かなり遅くなります。
考えてみると、ようやく理由がわかりました:-)
2 はバイナリで 0010 として表されます
-6 として 1010
0101として5つ
2 は 3 ビットだけで表現できるようになったため、010 として格納されます。
-6 は 010 として 3 ビットで格納されます
5 は 01 として 2 ビットに格納されます
したがって、最終的な出力は 2 2 1 になります
みなさん、お返事ありがとうございます!!!!