【C言語入門】ビットシフトとビットマスクを試してみた【ビット演算子】

C言語 C言語

今回はC言語でビット演算子(&、>>)を使ってデータを変化させて遊んでみようと思います。

・・・。

ビット演算子と改まって言うと変な感じがしますね。
仕事などで使う場合は、”ビットシフトする”とか”ビットマスクする”とか言うことが多い気がします。
個人的によく使う演算子は下記。

演算子簡単な説明
&アンド。0x81&0x80とすると、0x80となる。
|オア。0x81|0x02とすると、0x83となる。
>>右シフト。0x40>>1とすると、0x20となる。
<<左シフト。0x40<<1とすると、0x80となる。

ちなみに、数字の先頭を0xとすると、”16進数ですよ”の意味となります。

はじめに

こちらの記事で作成したフォルダに、今回もCソースを作成しようと思いますので、参考にどうぞ。

サンプルコード

いきなりですが、サンプルコードです。
今回は、エアコンからデータを受信したと仮定し、その受信データの内容をプリントしてみようという内容です。

/* インクルードファイル */
#include <stdio.h>

/* プロトタイプ宣言 */
unsigned char Get_Recv_Data(unsigned char *);
unsigned char GetBit(unsigned char *, unsigned char);

/*
   受信データ(recv_buf)の各ビットの意味を下記とする。
   Bit7   = 電源状態(0=OFF,1=ON)
   Bit6   = 運転モード(0=暖房,1=冷房)
   Bit5   = 強さ(0=弱,1=強)
   Bit4   = 首振り機能(0=OFF,1=ON)
   Bit3~0= 温度(0=18℃~15=33℃)
*/

/* メイン関数 */
void main(void) {
	unsigned char recv_buf;
	/* 外部装置からデータ受信 */
	Get_Recv_Data(&recv_buf);
	/* 電源状態取得(Bit7) */
	printf("電源は");
	if(GetBit(&recv_buf,7)){
		printf("ONです。\n");
	}else{
		printf("OFFです。\n");
	}
	/* 運転モード取得(Bit6) */
	printf("運転モードは");
	if(GetBit(&recv_buf,6)){
		printf("冷房です。\n");
	}else{
		printf("暖房です。\n");
	}
	/* 強さ取得(Bit5) */
	printf("エアコンの強さは");
	if(GetBit(&recv_buf,5)){
		printf("強です。\n");
	}else{
		printf("弱です。\n");
	}
	/* 首振り状態取得(Bit4) */
	printf("首振り機能は");
	if(GetBit(&recv_buf,4)){
		printf("ONです。\n");
	}else{
		printf("OFFです。\n");
	}
	/* 設定温度取得(Bit3~0) */
	printf("設定温度は%d℃です。\n",(recv_buf&0x0f)+18);
};
/* 以下、内部関数 */
/*****************************************************************/
/* 関数名:Get_Recv_Data(unsigned char *pbuf)                    */
/* 機能 :データ受信処理                                        */
/* メモ :ここでデータを受信する。                              */
/*     とりあえず受信するデータを直接書く。                  */
/*****************************************************************/
unsigned char Get_Recv_Data(unsigned char *pbuf){
	*pbuf = 0x80;/* 電源ONのみ */
}

/*****************************************************************/
/* 関数名:GetBit(unsigned char *pbuf, unsigned char bit)        */
/* 機能 :ビット取得処理                                        */
/* メモ :第一引数のバイトデータから、第二引数のビット位置の    */
/*     ビットを0または1で返す。                              */
/*****************************************************************/
unsigned char GetBit(unsigned char *pbuf, unsigned char bit){
	unsigned char ret=0;
	if(0<=bit && bit<=7){
		ret = (*pbuf>>bit)&0x01;
	}
	return(ret);
}

要点解説

21行目にて、受信データを取得します。
Get_Recv_Dataで、引数の*pbufに対して、0x80のデータを受信したと仮定します。(61行目)
23行目~51行目は、受信データの中身を判定し、プリント出力しています。

ここで、各判定にGetBit関数を使用しています。
GetBit関数は、第1引数のデータに第2引数の分だけビットシフトし、余計なビットをマスクしています。
第2引数の数値は0相対で指定しますので注意です。

あとがき

今回は1バイトデータで色々表現しました。
たかが1バイトですが、使い方によってはビットに様々な意味・状態を含ませる事ができます。

やり方によっては高速に処理ができたりとメリットもありますが、分かりにくかったり、
構造体でビットフィールドを使用する場合は、バイトオーダを意識したりしなくてはいけない等デメリットもあります。