今回はC言語のちょっとマイナーな機能をご紹介します。
ビットフィールド
ビットフィールドとは、簡単に言うと変数のメモリサイズをプログラマ側で指定することができるようにする技術のことです。
C言語においては通常int型は4バイト、char型は1バイトといったように定められていますが、ビットフィールドを用いることでこれらを変更することが可能です。
例えば、
typedef struct {
unsigned char b0;
unsigned char b1;
unsigned char b2;
unsigned char b3;
unsigned char b4;
unsigned char b5;
unsigned char b6;
unsigned char b7;
} NormalStruct;
このような構造体があったとします。この構造体のサイズは
char型の1バイト×8で8バイトとなります。これを以下のようにビットフィールドを用いて「[型名] [変数名] : [ビット数]」と指定してやると
typedef struct {
unsigned char b0 : 1;
unsigned char b1 : 1;
unsigned char b2 : 1;
unsigned char b3 : 1;
unsigned char b4 : 1;
unsigned char b5 : 1;
unsigned char b6 : 1;
unsigned char b7 : 1;
} Bitfield;
このようにビット単位でのサイズ指定が可能となり、メモリを節約できます。
現在は通信やメモリなどの大容量化が進み使う機会が減りましたが、筆者の前職では現役の技術でした。
共用体
構造体を教わる際についでにちょろっと語られることの多い共用体ですが、おそらく多くの方が「こんなの何に使うんだよ」と思われると思います。
実際使う機会は多くないと思いますが、見かけるときはだいたい上記のビットフィールドと合わせて使用されていました。
例えば、
typedef struct {
unsigned char b0 : 1;
unsigned char b1 : 1;
unsigned char b2 : 1;
unsigned char b3 : 1;
unsigned char b4 : 1;
unsigned char b5 : 1;
unsigned char b6 : 1;
unsigned char b7 : 1;
} Bitfield;
typedef union {
Bitfield bits;
unsigned char data;
} Operation;
このような共用体を用意すれば、フラグ管理などが容易に行なえます。
構造体Bitfieldの各変数をフラグと見立てて
void exec_op(unsigned char data)
{
Operation op;
op.data = data;
if(op.bits.b0){
/* 処理1 */
}
if(op.bits.b1){
/* 処理2 */
}
if(op.bits.b2){
/* 処理3 */
}
~ 略 ~
などのような処理が行なえます。
これらのメリットは、メモリの節約、ほとんどの操作が「メンバ変数 data」への代入・送信・受信などで終結可能なことです。
初期化も「data=0;」とすればいいので開発パフォーマンスも上がります。
関数ポインタ
これはマイナーどころかドメジャーですが、覚えとくと便利なのでついでに載せときます。
typedef struct {
int id;
void (*func)();
} Event;
Event evt[EVENT_MAX];
int add(int evtno, void (*pfunc)())
{
evt[evtno].id = evtno;
evt[evtno].func = pfunc;
~ 略 ~
みたいな感じで関数の引数に関数を渡したり、配列に関数を格納したりできます。
呼び出すときは
evt[evtno].func();
って感じです。
まとめ
最近Pythonばかり触ってたのでC言語も触っとかないとな~と思い記事にしました。
なんだかんだで今だによく使われてる言語ですので。
コメント