3

私は、char が 1 バイトを取るウィンドウでターボ C に取り組んでいます。今、私の問題は以下のユニオンにあります。

union a
{
 unsigned char c:2;
}b;
void main()
{
printf("%d",sizeof(b));  \\or even sizeof(union a)
}

このプログラムは出力を 2 として出力していますが、ユニオンは 1 バイトしかとらないはずです。なぜそうなのですか?

構造体の場合、1バイトを指定しても問題ありませんが、この共用体は不適切に機能しています。

そして、これらのビット フィールドにアクセスする方法がもう 1 つあります。

scanf("%d",&b.c);  //even scanf("%x",b.c);

ビットのアドレスを取得できないため、機能していません。したがって、以下のような別の変数を使用する必要があります

int x;
scanf("%d",&x);
b.c=x;

避けられないの??他に方法はありますか???

4

6 に答える 6

9

コンパイラーは構造体と共用体にパディングを追加することができますが、1 バイトの構造体を取得できる場合に共用体を 2 バイトのサイズに丸めるのは少し驚くべきことだと認めますが、それは完全に許可されています。

2 番目の質問への回答: いいえ、避けられません。ビット フィールドは構造体のパッキングの最適化であり、ビット フィールド メンバーが個別にアドレス指定できないというパフォーマンスと利便性の面でのデメリットがあります。

于 2008-11-14T12:24:10.553 に答える
4

Turbo C は、2 バイトのワード境界を持つ 8086 マイクロプロセッサに基づいています。アトミックな読み取りと書き込みは通常、CPU のアーキテクチャにバインドされているため、コンパイラはデータ構造を整列させるためにスラック バイトを追加しています。

代替テキスト

呼び出し#pragma pack(1)で無効にできるかもしれませんが、Turbo C で動作するかどうかはわかりません。

于 2008-11-14T12:55:36.607 に答える
1

回答には多くの誤報があるので、明確にします。2 つの理由のいずれかが考えられます (私はコンパイラに詳しくありません)。

  1. ビットフィールドの記憶単位は 2 です。

  2. アラインメントはワード (2 バイト) 境界に強制されます。

ビットフィールドストレージユニットを宣言された「ベース」タイプのサイズとして取るのは一般的な拡張であるため、これが最初のケースであるとは思えません。この場合、型は常にサイズが 1 の char です。

[標準では、int型またはunsigned int型のビットフィールドのみを宣言でき、ビットフィールドがグループ化される「ストレージユニット」は固定されています(通常、intと同じサイズ)。単一ビットのビットフィールドでさえ、1 つのストレージユニットを使用します。]

#pragma pack2 番目のケースでは、アラインメントを制御できるように C コンパイラが実装するのが一般的です。デフォルトのパッキングは 2 であると思われます。この場合、ユニオンの最後にパッド バイトが追加されます。これを回避する方法は、次を使用することです。

#pragma pack(1)

また、afterward を使用#pragma pack()してデフォルトに戻す必要があります (または、コンパイラでサポートされている場合は、push および pop 引数を使用することをお勧めします)。

コンパイラの動作に我慢しなければならないと言ったすべての返信者にとって、これは C の精神に反しています。制御できない状況では、ビットフィールドを使用して、任意のサイズまたはビット順序にマップできるはずです。ファイル形式やハードウェア マッピングなど。

もちろん、実装が異なれば、バイト順序、ビットフィールド記憶装置にビットが追加される順序 (上からまたは下から)、記憶装置のサイズ、デフォルトのアライメントなどが異なるため、これは非常に移植性がありません。

2番目の質問については、問題があるので使用したことはありませんが、問題がわかりませんscanf

于 2010-02-01T11:55:43.960 に答える
1

ユニオンが正確に最小サイズでなければならないという要件がどこにあるのかわかりません。オブジェクトは少なくともそのメンバーと同じ大きさでなければなりませんが、それは下限にすぎません。

ビットフィールドのアドレスを取得することはできません。そのタイプは何でしょう?int* にすることはできません。scanf(%d) は、渡した int* に sizeof(int) * CHAR_BIT ビットを書き込みます。これは 2 ビット以上を書き込みますが、そのスペースがありません。

于 2008-11-14T12:22:07.423 に答える
1

標準には、構造体の最初のメンバーの前にパディングがないことを示す段落があります。しかし、組合については明示的にそうは言っていません。ユニオンを 2 バイト境界でアラインする必要があるため、サイズの違いが生じる可能性がありますが、構造体の最初のメンバーの前にパディングできないため、構造体は 1 バイトでアラインされます。また、共用体にはさまざまなタイプのメンバーをさらに含めることができるため、共用体に必要なアライメントが広がる可能性があることに注意してください。たとえば、ユニオンの必要なアラインメントに従って処理する必要があるコードを容易にするために、コンパイラが少なくとも 2 バイトのアラインメントを与える理由がある場合があります。

とにかく、共用体が正確に 1 バイトでなければならないという要件はありません。すべてのメンバーのための場所が必要です。

2番目の質問についてC標準が言わなければならないことは次のとおりです。

The operand of the unary & operator shall be either a function designator or an lvalue that designates an object that is not a bit-field and is not declared with the register storage-class specifier.

したがって、最善の策は、int を使用して自分のやり方を使用することです。コードを中かっこで囲むと、一時変数はローカルに保持されます。

void func(void) { struct bits f; { int x; scanf("%d", &x); f.bitfield = x; } /* ... */ }
于 2008-11-14T12:26:55.900 に答える
0

「構造体または和集合の終わりに名前のないパディングがある場合もある」という事実に加えて、コンパイラは「ビットフィールドを保持するのに十分な大きさのアドレス可能なストレージユニット」にビットフィールドを配置することが許可されます。(どちらの引用もC90標準からのものです。C99標準と似ていますが異なる表現があります)。

また、標準では「ビットフィールドはint、unsigned int、signed intの修飾または非修飾バージョンであるタイプでなければならない」と規定されているため、char型にビットフィールドを含めることは非標準であることに注意してください。

ビットフィールドの動作は、指定されていないコンパイラ実装の詳細に大きく依存するため(ビットフィールドには、私が言及していない他のいくつかの移植性のない問題があります)、それらを使用することはほとんどの場合悪い考えです。特に、ファイル形式、ネットワークプロトコル、またはハードウェアレジスタでビットフィールドをモデル化しようとする場合、これらはお勧めできません。


別のSO回答からの詳細情報:

一般に、ビットフィールドを避け、フィールド内の「サブフィールド」にアクセスするために、明示的なビットマスキングとシフトを伴う他のマニフェスト定数(列挙型など)を使用する必要があります。

ビットフィールドを避ける必要がある理由の1つは、同じプラットフォームであってもコンパイラ間での移植性が低いことです。C99標準から(C90標準にも同様の表現があります):

実装は、ビットフィールドを保持するのに十分な大きさのアドレス可能なストレージユニットを割り当てることができます。十分なスペースが残っている場合、構造内の別のビットフィールドの直後に続くビットフィールドは、同じユニットの隣接するビットにパックされます。十分なスペースが残っていない場合、収まらないビットフィールドが次のユニットに配置されるか、隣接するユニットとオーバーラップするかは、実装によって定義されます。ユニット内のビットフィールドの割り当て順序(高次から低次または低次から高次)は、実装によって定義されます。アドレス指定可能なストレージユニットの配置は指定されていません。

ビットフィールドがint境界に「またがる」かどうかを保証することはできません。また、ビットフィールドがintのローエンドで始まるか、intのハイエンドで始まるかを指定することもできません(これは、プロセッサがビッグエンディアンまたはリトルエンディアン)。

于 2008-11-14T17:49:40.197 に答える