27063


初めて質問します。知識不足のせいか一部、一部おかしくな記述があるかもしれませんが、それを承知の上で質問に応えていただければ幸いです。

以下のような構造体があったとします。

[code]

    struct Sample{
        unsigned char var_a: 4;
        unsigned char var_b: 1;
        unsigned char var_c: 2;
        unsigned char var_d: 1;
    
    
        unsigned char var_e;  
    };
    
[/code]

上記の構造体は(4bit,1bit,2bit,1bit)、(8bit)がメモリに確保されているため、合計2Byte確保されているはずです。

問題は以下のようなことをした際に、ビットフィールドにビットを直接代入できると思っていました。

[code]

    unsigned short int var_1 = 0x0010;
    
    struct Sample sample;
    sample.var_a = var_1 & 0x00f0;
    /* {0000 0000 0001 0000} & {0000 0000 1111 0000} = {0000 0000 0001 0000} */
    
[/code]

0x0010と0x00f0の論理積なので答えは0x0010であり、0001の4ビットをsample.var_aに代入できると思っていました。({0000
0000 |0001| 0000}の||で囲んだ4ビットのこと)

printf("%x \n",sample.var_a);で出力すると、実際には0が代入されていました。  
{0000 0000 00001
|0000|}の(0,1,2,3)bitの0000を代入していたと後から気づいたのですが、これを(4,5,6,7)bitの0001をsample.var_aに代入することはできないのでしょうか。  
  
  
追記:  
一部、誤字があったので修正です。

[code]

    struct Sample hoge;
    
[/code]

ではなく、

[code]

    struct Sample sample;
    
[/code]

でした。

書いていた途中で変えてしまっていました。わかりにくいようにしてしまい大変失礼いたしました。


CC BY-SA 3.0
2016-06-25T07:52:22.077
27060
2016-10-06T06:23:17.660
2016-06-25T15:27:26.763
16947
16947
question
c++ c
C言語の構造体のビットフィールドに直接ビットを埋め込むことは可能ですか


（以下`sample`->`hoge`だと仮定して）  
4ビットシフトすればよいかと思います。

[code]

    hoge.var_a = (var_1 & 0x00f0) >> 4;
    
[/code]


CC BY-SA 3.0
2016-06-25T08:43:20.670
27061
2016-06-25T08:43:20.670
13199
27060
answer


言語規格書が定めている厳密な話はちょっと置いておくことにします。

ビットフィールドは、「そのビットの整数」と解釈されます。  
提示 `var_a` は、メモリ上実際に配置されるビット位置が bit3-bit0 であろうが bit7-bit4 であろうが  
４ビットの符号なし整数として扱う約束です。そのため 0..15 の値が格納できるわけです。  
（そうなるようにコンパイラがシフト演算 and/or 演算を生成する約束です）

同様 `var_b` は 0 か 1 かが格納できる数として扱われます。

言語仕様書はサイズの大きな整数からサイズの小さな整数に格納が行われるとき、  
\- 格納できない上位ビットは捨てて  
\- 格納できる下位ビットだけを格納する  
ことを定めています。

(２進数表記した)値 `1111 1101 0110 1001` を  
`var_a` に格納する場合は下位４ビット、つまり `1001`  
`var_b` に格納する場合は下位１ビット、つまり `1`  
となってしまいます。  
なので既に回答にある通り、下位ビットでない値を格納したい場合にはシフト演算が必要です。

この例では、自分で元数値のシフト演算を行っているのに、  
ビットフィールド操作でコンパイラがまた別のシフト演算を行うことになるので  
機械語的には複数の演算が入ることになり、美味しくないです。  
ならば最初からビットフィールドなど使わず `unsigned short int` で直接演算したほうが  
わかりやすくて移植性が良いコードになりそうな気がします。


CC BY-SA 3.0
2016-06-25T09:40:19.197
27063
2016-06-25T09:40:19.197
8589
27060
answer


言語仕様的な話をすると

  * ビットフィールドのデータ型は`_Bool`、`signed int`、`unsigned int`のいずれかであり、他の型を使用できるかは実装依存です。
  * ビットフィールドのビット配置も実装依存であり`var_a`が何ビット目に収められるかの保証はありません。

といった事情もあり、移植性のあるコードを書こうとする場合にもビットフィールドを使用せず、直接シフト・ビット演算した方がいいこともあります。


CC BY-SA 3.0
2016-06-25T15:20:17.810
27076
2016-06-25T15:20:17.810
4236
27060
answer


VisualStudioでデフォルトオプションと仮定すると、こんなのはいかがでしょうか。

[code]

    union U{
        struct Sample{
            unsigned char var_d : 1;
            unsigned char var_c : 2;
            unsigned char var_b : 1;
            unsigned char var_a : 4;
            unsigned char var_e;
        } st;
        unsigned short raw;
    };
    
    unsigned short v1 = 0x0010;
    U tmp;
    tmp.raw = v1;
    printf("var_a : %x \n", tmp.st.var_a);
    
[/code]

対象CPUやコンパイラによるビットフィールド構造体の宣言順番に関しては 774RR さん sayuri さんと同意見です。


CC BY-SA 3.0
2016-10-06T06:23:17.660
29387
2016-10-06T06:23:17.660
19046
27060
answer