3

私はちょうどビット フィールドをいじっていたところ、回避方法がよくわからないものに出くわしました。

(プラットフォームに関する注意: int のサイズ = 2 バイト、long = 4 バイト、long long = 8 バイト - 異なる可能性があることを知っているので、言及する価値があると考えました。また、「byte」型は「unsigned char」として定義されています)

2 つの 36 ビット変数の配列を作成し、それらを 9 バイトの配列で結合できるようにしたいと考えています。これは私が思いついたものです:

typedef union {
  byte bytes[9];
  struct {
    unsigned long long data:36;
  } integers[2];
} Colour;

私は、匿名構造体の一部として 2 つのビットフィールドが存在することになっていることをコンパイラが認識し、それらを 9 バイトのスペースにまとめるという理論に取り組んでいました。ただし、それらはバイト境界で整列されることが判明したため、共用体は 9 バイトではなく 10 バイトを占有します。これは完全に理にかなっています。

問題は、このような 2 つのビット フィールドの配列を作成する方法があるかどうかです。「packed」属性を考慮しましたが、コンパイラはそれを無視します。

これは期待どおりに機能しますが (sizeof() は 9 を返します):

typedef union {
  byte bytes[9];
  struct {
    unsigned long long data0:36;
    unsigned long long data1:36;
  } integers;
} Colour;

配列としてアクセスできるようにすることが望ましいでしょう。


編集: これが機能しない理由について説明してくれた cdhowie に感謝します。

幸いなことに、私が望むものを達成する方法を考えました:

typedef union {
  byte bytes[9];
  struct {
    unsigned long long data0:36;
    unsigned long long data1:36;
    unsigned long long data(byte which){
      return (which?data1:data0);
    }
    void data(byte which, unsigned long long _data){
      if(which){
        data1 = _data;
      } else {
        data0 = _data;
      }
    }
  } integers; 

} Colour; 
4

1 に答える 1

6

各ビットフィールドを正確に36ビット幅にしたい場合は、配列を使用してこれを直接行うことはできません。

ポインタはバイト境界に揃える必要があります。これは、ポインタと同じです。配列はほとんどの場合(例外を除いて)ポインタのように機能するため、8で割り切れないビット数を含むビットフィールドではこれは不可能です(&(((Colour *) 0)->integers[1])ビットフィールドがパックされた場合に何が返されると思いますか?どの値が意味をなしますか? ?)

2番目の例では、内部でポインター計算が行われていないため、ビットフィールドを密に詰めることができます。バイトはポインタを「測定」するために使用される単位であるため、ポインタでアドレス指定できるようにするには、バイト境界に収まる必要があります。

(((Colour *) 0)->integers.data0)2番目の例のまたはのアドレスを取得しようとするとdata1、まさにこの理由で、コンパイラがエラーを発行することに注意してください。

于 2012-10-17T17:49:02.543 に答える