8

重複の可能性:
ビットフィールドをintに変換

私はアプリケーションに取り組んでいます。その一部は、多数の1ビットフラグを含む16ビットワードを処理します。以下に示すような構造を使用してデータを処理しています。

struct mystruct
{
   uint16_t Reserved1   :3;
   uint16_t WordErr     :1;
   uint16_t SyncErr     :1;
   uint16_t WordCntErr  :1;
   uint16_t Reserved2   :10;
};

つまり、構造体には1つの16ビット変数が含まれており、これは多数の小さい(場合によっては1ビットフラグ)ピースとして処理されます。

私の質問はこれです。たとえば、16ビットワード全体を1つの値として処理して、コンソールやファイルに出力したり、別のデータ構造に追加したりする簡単な方法はありますか?個々の構造要素をシフトして一時的なuint16_t変数に追加する以外に、これを行う方法はわかりません。単語全体を抽出するもっと簡単な方法があるようですが、コンパイラがこのような構造をどのように処理するかについての情報は見つかりません。

編集:これは明らかかもしれませんが、私が一言で言えば、1ビットフラグに個別にアクセスでき、構造をuint16_t型の単一変数(つまり、unsigned short、16ビット)として使用できます。 )。

4

4 に答える 4

11

ここでの標準的なアプローチは、次のように匿名の構造体/共用体を使用することです。

union mystruct
{
   struct
   {
      uint16_t Reserved1   :3;
      uint16_t WordErr     :1;
      uint16_t SyncErr     :1;
      uint16_t WordCntErr  :1;
      uint16_t Reserved2   :10;
   };

   uint16_t word_field;
};

または、ユニオンがトップレベルのオブジェクトとして適切でない場合、

struct mystruct
{
   union
   {
       struct
       {
          uint16_t Reserved1   :3;
          uint16_t WordErr     :1;
          uint16_t SyncErr     :1;
          uint16_t WordCntErr  :1;
          uint16_t Reserved2   :10;
       };

       uint16_t word_field;
   };
};

この定義により、次のような内部フィールドへの直接アクセスが可能になります。

mystruct s1;
s1.WordCntErr = 1;

厳密に言えば、コンパイラは、共用体のさまざまなメンバーが互いにどのようにオーバーラップするかについて何の保証も与えていません。さまざまな配置やシフトを使用できます。ここで多くの人がすぐにこれを指摘します。それにもかかわらず、実際的な観点からこれを見ると、共用体のすべてのフィールドが同じサイズである場合、それらが同じメモリを占有していると安全に想定できます。たとえば、コード

s1.word_field = 0;

すべてのビットフィールドをゼロにします。大量のコードがこれを使用しています。これが機能しなくなることは考えられません。

于 2012-09-18T18:34:26.620 に答える
4

短い答えは、あなたにはできないということです。より長い答えは、それを行うことができるということですが、詳細はコンパイラによって異なります。この特定のビット フィールド レイアウトは、ハードウェア レジスタにマップすることになっているように疑わしく見えます。この場合、既にコンパイラの依存関係があります。ビット フィールドがどのように配置されるかの詳細は、実装によって定義されます。したがって、コンパイラが期待どおりにレイアウトすることを確認しながら、共用体を介して型駄洒落をサポートしているかどうかを確認することもできます。C と C++ の両方で、共用体の 1 つのフィールドに書き込み、別のフィールドから正式に読み取ると、未定義の動作が生成されますが、ほとんどの (すべて?) コンパイラは、このような単純なケースでそれをサポートします。

于 2012-09-18T18:48:52.007 に答える
2

ユニオン手法による未定義の動作の代わりに、データをコピーできます。

mystruct m;
m.Reserved1 = 0;
m.WordErr = 1;
m.SyncErr = 0;
m.WordCntErr = 0;
m.Reserved2 = 0;

uint16_t value = 0;
memcpy(&value, &m, sizeof(value));

[コード]

もちろん、出力はプラットフォーム固有/エンディアンに依存するため、再度読み取ることができるように出力する予定がある場合は、それを考慮してください。

于 2012-09-18T22:10:18.360 に答える
1

そのための組合です。私はこれを使う必要はほとんどないので、私の構文はさびているかもしれませんが、次のようになります:

union myunion
{
    struct mystruct
    {
       uint16_t Reserved1   :3;
       uint16_t WordErr     :1;
       uint16_t SyncErr     :1;
       uint16_t WordCntErr  :1;
       uint16_t Reserved2   :10;
    };
    uint16_t word;
};

もちろん、アクセスするたびに入力が追加されるため、たまにしか必要ない場合は、型キャストを試してみることをお勧めします。

于 2012-09-18T18:32:20.183 に答える