【C言語】
ビット演算とマスクパターンのよくある間違い

■この記事の概要

この記事では、C言語でのビット演算子とマスクパターンのよくある誤りを解説しています。

特に、if文でのビット演算の結果が常に真や偽になるケースを紹介し、その原因を詳しく説明しています。

具体的なコード例も提供され、間違いを理解するための参考になります。


■bitwise comparison always evaluates to true

#include    <stdio.h>
void f(unsigned int x){
    if((x | 1) == 0)    puts("ここには来ない");
    else                puts("常時偽");    
    if((x & 0) == 0)    puts("常時真");
    else                puts("ここには来ない");

    if((x | 1) != 0)    puts("常時真");
    else                puts("ここには来ない");    
    if((x & 0) != 0)    puts("ここには来ない");
    else                puts("常時偽");
}
int main(void){
    f(0);
    f(1);
}

if(x|1)👉必ず真
if(x&0)👉必ず偽
となるのでif文判定に意味がありません。

➡実行結果

./a.out
常時偽
常時真
常時真
常時偽
常時偽
常時真
常時真
常時偽

■ビット演算子とシフト演算子の間違い

#include <stdio.h>
int main(void){
    unsigned int bit = 0x80;
    puts("間違い1");
    for(unsigned int i = 0;i <= 7;i++){
        if(bit & (0<<i)){
            printf("%ubitが立ってます\n",i);
        } 
    }
    puts("間違い2");
    for(unsigned int i = 0;i <= 7;i++){
        if(bit | (1<<i)){
            printf("%ubitが立ってます\n",i);
        } 
    }
    puts("正しい");    
    for(unsigned int i = 0;i <= 7;i++){
        if(bit & (1<<i)){
            printf("%ubitが立ってます\n",i);
        } 
    }
}

if(bit & (0<<i)){👉必ず偽
if(bit | (1<<i)){👉必ず真
となるのでif文判定に意味がありません。

➡実行結果

./a.out
間違い1
間違い2
0bitが立ってます
1bitが立ってます
2bitが立ってます
3bitが立ってます
4bitが立ってます
5bitが立ってます
6bitが立ってます
7bitが立ってます
正しい
7bitが立ってます

■bitwise comparison always evaluates to false

#include    <stdio.h>
#include    <stdint.h>
char *f(unsigned short x){
    if((x & 2) == 1)                return  "常に不成立";
    if((x & 0b0010U) == 0b0001U)    return  "常に不成立";    
    if((x & 0xFF00U) == 0x00FFU)    return  "常に不成立";
    if((x & 0x00FFU) == 0xFF00U)    return  "常に不成立";
    return  "必ずここに来る";
}
int main(void){
    printf("%s\n",f(0));
    printf("%s\n",f(1));
    printf("%s\n",f(2));
    printf("%s\n",f(0x00FF));
    printf("%s\n",f(0xFF00));
    printf("%s\n",f(0xFFFF));
}

ビットパターンがあっていないので
if文が成立する事はありません。


■Mismatching bitmasks. Result is always 0

[(style)mismatchingBitAnd]

#include    <stdio.h>
typedef unsigned int uint32_t ;
void f(uint32_t y)
{
    uint32_t x = y & 0xFFFF0000U; 
    uint32_t z = x & 0x0000FFFFU ; 
    printf("%x\n",z);
}

上記のマスクパターンでは
yの値に無関係に
zの値は0になります。


Boolean expression ‘b’ is used in bitwise operation.

警告:bool変数をビット演算に使用した
[(style)bitwiseOnBoolean]

#include    <stdio.h>
#include    <stdbool.h>
char *f(bool b){
    if(b & 2U)  
        return  "到達不能";
    else
        return  "ビットパターンがマッチする事はない";
}
int main(void){
    printf("%s\n",f(0));
    printf("%s\n",f(1));
    printf("%s\n",f(2));
    printf("%s\n",f(3));
}

if(b & 2U)でbool変数は0/1しかとらないので2UとビットANDをとる意味がありません。


ビット演算の結果をtrueと比較するのは多分間違い

#include <stdio.h>
#include <stdbool.h>

#define     BIT7    (1U<<7)

//7bit目が立っているか?を判定する正しい方法は?
int main(void)
{
    unsigned char x = BIT7;
    
    if((x & BIT7) == 1)     puts("A");
    if((x & BIT7) == true)  puts("B");
    if((x & BIT7) != 0)     puts("C");
    if((x & BIT7) != false) puts("D");
    if((x & BIT7) == BIT7)  puts("E");
    if(x & BIT7)            puts("F");
}

(A)x&BIT7が1になる事はありません。
(B)同上
(C)意図した動きをします
(D)同上
(E)社内規約で推奨する場合があります。
(F)筆者は明解なこの書き方を推奨します。


■アンケート

3
7bit目が立っているか?を判定する正しい方法は?

参考:

EXP17-C. 条件式に対してビット単位の演算を行わない