C言語:ビットフィールド
SPINのstate vector(状態ベクトル?)が気になってデバッグしているときに、pan.cでビットフィールドが使われている箇所を見つけました。
C言語の本で存在は知っていたのですが、使用したこともなく、また実際のコードで見たのは初めてでした。state vectorの理解にも必要になりそうだったので、pan.cを参考にコードを作成し動作を確認してみました。
確認に使用したコードは以下のものになります。
ソース bitfield.c
#include <stdio.h> #include <string.h> /* ビットフールドを使用した構造体 */ struct P1 { unsigned int _pid : 8; unsigned int _t : 3; unsigned int _p : 3; }; /* pan.cのソースコードを参考にダンプ用の関数を作成 */ void dumpstate(struct P1 *p) { int i; char *cp = (char *)p; for (i = 0; i < sizeof(struct P1); i++, cp++) { printf("%d,", *cp); } putchar('\n'); cp = (char *)p; for (i = 0; i < sizeof(struct P1); i++, cp++) { printf("0x%02x,", *cp); } putchar('\n'); } int main(void) { struct P1 p1; memset(&p1, 0x00, sizeof(struct P1)); dumpstate(&p1); p1._pid = 1; dumpstate(&p1); p1._t = 1; dumpstate(&p1); p1._p = 1; dumpstate(&p1); p1._pid = 0xff; dumpstate(&p1); p1._t = 3; dumpstate(&p1); p1._p = 3; dumpstate(&p1); return 0; }
コンパイルから実行まで
gdbでデバッグも行いたいので -g3 オプションを付与してコンパイルしています。
コンパイルと実行結果
$ gcc -Wall -g3 bitfield.c $ ./a.out 0,0,0,0, 0x00,0x00,0x00,0x00, 1,0,0,0, <- p1._pid = 1 の実行後 0x01,0x00,0x00,0x00, 1,1,0,0, <- p1._t = 1 の実行後 0x01,0x01,0x00,0x00, 1,9,0,0, <- p1._p = 1 の実行後 0x01,0x09,0x00,0x00, -1,9,0,0, 0xffffffff,0x09,0x00,0x00, <- p1._pid = 0xff の実行後 -1,11,0,0, 0xffffffff,0x0b,0x00,0x00, <- p1._t = 3 の実行後 -1,27,0,0, 0xffffffff,0x1b,0x00,0x00, <- p1._p = 3 の実行後
gdbでの実行
$ gdb ./a.out GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git Copyright (C) 2018 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type "show copying" and "show warranty" for details. This GDB was configured as "x86_64-linux-gnu". Type "show configuration" for configuration details. For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. Find the GDB manual and other documentation resources online at: <http://www.gnu.org/software/gdb/documentation/>. For help, type "help". Type "apropos word" to search for commands related to "word"... Reading symbols from ./a.out...done. (gdb) break main Breakpoint 1 at 0x7f3: file bitfield.c, line 32. (gdb) run Starting program: /home/makoto/blog/12/a.out Breakpoint 1, main () at bitfield.c:32 32 { (gdb) n 35 memset(&p1, 0x00, sizeof(struct P1)); (gdb) 36 dumpstate(&p1); (gdb) 0,0,0,0, 0x00,0x00,0x00,0x00, 38 p1._pid = 1; (gdb) p sizeof(struct P1) $1 = 4 (gdb) x/4tb &p1 0x7fffffffdc74: 00000000 00000000 00000000 00000000 (gdb) n 39 dumpstate(&p1); (gdb) n 1,0,0,0, 0x01,0x00,0x00,0x00, 41 p1._t = 1; (gdb) x/4tb &p1 0x7fffffffdc74: 00000001 00000000 00000000 00000000 ^^^^^^^^_pid部分 (gdb) n 42 dumpstate(&p1); (gdb) n 1,1,0,0, 0x01,0x01,0x00,0x00, 44 p1._p = 1; (gdb) x/4tb &p1 0x7fffffffdc74: 00000001 00000001 00000000 00000000 ^^^_p部分 (gdb) n 45 dumpstate(&p1); (gdb) 1,9,0,0, 0x01,0x09,0x00,0x00, 47 p1._pid = 0xff; (gdb) x/4tb &p1 0x7fffffffdc74: 00000001 00001001 00000000 00000000 ^^^_t部分 (gdb) n 48 dumpstate(&p1); (gdb) -1,9,0,0, 0xffffffff,0x09,0x00,0x00, 50 p1._t = 3; (gdb) x/4tb &p1 0x7fffffffdc74: 11111111 00001001 00000000 00000000 ^^^^^^^^_pid部分 (gdb) n 51 dumpstate(&p1); (gdb) -1,11,0,0, 0xffffffff,0x0b,0x00,0x00, 53 p1._p = 3; (gdb) x/4tb &p1 0x7fffffffdc74: 11111111 00001011 00000000 00000000 ^^^_p部分 (gdb) n 54 dumpstate(&p1); (gdb) -1,27,0,0, 0xffffffff,0x1b,0x00,0x00, 56 return 0; (gdb) x/4tb &p1 0x7fffffffdc74: 11111111 00011011 00000000 00000000 ^^^_t部分 (gdb) n 57 }
構造体とメモリ
上記のようにgdbでp1を保存しているメモリをバイナリダンプで出力した結果を見ると、私の環境では以下のようになっているということですね。
+0バイト +1バイト アドレス iiiiiiii 00tttppp ^^^^^^^^ |||--- ^ : _pid 部分 8ビット - : _p 部分 3ビット | : _t 部分 3ビット
_pと_tとメモリの位置を間違えてしまいそうです。