ttの日記: オレオレビットフィールドを作る 4
人生初のAdvent Calendarをしてみんとしてなんとなく久々に日記など。
C言語 Advent Calendar 2016 の6日目、らしい。
Cの世界にはビットフィールドというのがある。もともとハードウェアレジスタを操作するために作られたと思われるが、今やメモリ削減のために使われている感がある(ex. webkit)。
どうしてこうなったか…というとまあ規格上いろいろと自由度と不自由度がありすぎて、エンディアンとかintの大きさとかによって「実際の」ビットの位置がずれてしまい、移植性のあるコードを書くのがめんどくさいからである。
ハードウェアを触るなんてマシン固有だからどーでもいいじゃん、というのはあるんだが、x86でもx86-64でも動いてほしいとか、ARM BEとARM LEで~とか、いろいろあるのである。
前振りが長くなった。さて本題。
ビットフィールド使えないとなるとレジスタ操作系のコードはこういうのになる
int reg = MMIO_REG_READ(COMMON_REG_ADDR);
int busy = (((reg >> STATUS_BIT_POS) & STATUS_BIT_LEN) == STATUS_BUSY);
わかりやすい。というか超べたべただ。
マクロなりなんなりで
int busy = (extract(reg, STATUS_BIT_POS, STATUS_BIT_LEN) == STATUS_BUSY);
なんて書くのも可能だし、マクロの定義を適度にいじってintのサイズ違いに対処とかもできそうだ。
と、ここまではよく見るんだけど、最近
extract(reg, STATUS_BIT_POS : STATUS_BIT_LEN)
みたいな書き方があるのを知った。
どーやってるんだろうとおもったら、こういう感じらしい
# define GETPOS(field) (0 ? field)
# define GETLEN(field) (1 ? field)
# extract(reg, field) (((reg)>>GETPOS(field))&((1uGETLEN(field)-1))
そう、三項演算子を使うらしい。
で、これの利点だけど…ハードウェアの仕様書とかではビットフィールドの記述に「:」を使うのは多いため、見た目がわかりやすい、ということ以外にあんまり思い浮かばなかった(笑)。C++はともかく、Cでは三項演算子やラベル名以外で:を使うというのはあんまりないので、他より目立たせることができる、というのもあるだろうか。
あんまり意味がないけど、まあ、面白いのでご紹介、ということで。