■この記事の概要
この記事では、C言語でのビット演算子とマスクパターンのよくある誤りを解説しています。
特に、if
文でのビット演算の結果が常に真や偽になるケースを紹介し、その原因を詳しく説明しています。
具体的なコード例も提供され、間違いを理解するための参考になります。
■ビット演算子の基本(AND)
#include <stdio.h>
int main(void){
printf("0 & 0 = %x\n",0 & 0);
printf("0 & 1 = %x\n",0 & 1);
printf("1 & 0 = %x\n",1 & 0);
printf("1 & 1 = %x\n",1 & 1);
}
./a.out
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
ビットごとのAND演算を行います。
両辺とも1ならば1になります。
■ビット演算子の基本(OR)
#include <stdio.h>
int main(void){
printf("0 | 0 = %x\n",0 | 0);
printf("0 | 1 = %x\n",0 | 1);
printf("1 | 0 = %x\n",1 | 0);
printf("1 | 1 = %x\n",1 | 1);
}
./a.out
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
ビットごとのOR演算を行います。
両辺のどちらかでも1ならば1になります。
■ビット演算の結果を2進数で表現する
#include <stdio.h>
void to_binary(int number) ;
int main(void){
to_binary(
0b1001
& 0b1010 //AND
);// 0b1000
to_binary(
0b1001
| 0b1010 //OR
);// 0b1011
}
void to_binary(int number) {
// ビット数を固定4ビット整数と仮定)
const int BITS = sizeof(char) * 4;
char binary[BITS + 1]; // 終端文字('\0')のために+1
binary[BITS] = '\0'; // 文字列終端
for (int i = BITS - 1; i >= 0; i--) {
binary[i] = (number & 1) ? '1' : '0'; // LSBからビット取得
number >>= 1; // 右シフト
}
printf("2進数: %s\n", binary);
}
./a.out
2進数: 1000
2進数: 1011
C99仕様までのC言語のprintfでは2進数表記が出来ないので、自作する必要があります。
■|と&は間違えやすい
// |と&を間違える
#include <stdio.h>
int main(void){
int x = 0;
if(x | 1){
puts("間違った書き方:常に成り立つ");
}
if(x & 1){
puts("正しい書き方");
}
}
プログラマと言えどもビット演算子は
四則演算より馴染みが少ないので、
|(OR)と&(AND)は間違いやすいです。
■&と==の結合力を間違える
//結合力の誤り
//warning: suggest parentheses around comparison in operand of ‘&’
//[-Wparentheses]
#include <stdio.h>
int main(void){
int x = 2;
if(x & 2 == 2){
puts("間違った書き方:(2==2)で結合");
}
if((x & 2) == 2){
puts("正しい書き方");
}
}
==は&より結合力が強いので
if(x & 2 == 2){は
if(x & (2 == 2)){とコンパイラは解釈します。
■ビットパターンを間違える
//ビットパターンの不一致
#include <stdio.h>
int main(void){
int x = 2 ;
if((x & 2) == 1) puts("NG");
if((x & 2) == 2) puts("OK");
int y = 0b0010 ;
if((y & 0b0010) == 0b0001) puts("NG");
if((y & 0b0010) == 0b0010) puts("OK");
}
1(0b0001)と
2(0b0010)はビットパターンが重ならないので
if((x & 2) == 1)が成立する事はありません。
■ビット演算の結果をtrueと比較すると間違いやすい
//ビット演算の結果を true と比較する間違い
//warning: bitwise comparison always evaluates to false
//[-Wtautological-compare]
#include <stdio.h>
#include <stdbool.h>
int main(void){
int x = 2 ;
if((x & 2) == true)
puts("間違い");
if((x & 2) == 1)
puts("間違い");
if((x & 2) == 2)
puts("良い");
if(x & 2)
puts("とても良い:明示的に==2の比較は不要");
}
true/falseは論理演算で使う定数なので
ビット演算に使用すると間違いやすいです。
又、
if((x&mask)==mask)のパターンは
maskが2のべき乗の時、
==maskは省略できます。
■0と1を間違えてビットオフ判定をする
//0と1を間違える
#include <stdio.h>
unsigned int bit ;
int main(void){
bit &= ~(1<<7);//7bitを下げる
if(bit & (0<<7)){
puts("間違った書き方");
}
if((bit & (1<<7)) == 0){
puts("正しい書き方");
}
}
特定のビットが下がっているか判定する時
(ビットオフ判定する時)0と1を間違った例です。
if(bit & (0<<7))ではbitの値に関係なく常時偽です。
参考: