【C言語の演算子】
ビット演算子の優先順位は危険
if(x & 2 == 2)はバグ

warning: suggest parentheses around comparison in operand of ‘&’

警告:&ビット演算子の回りにカッコつけよう
[-Wparentheses]


■1.ビット演算子がラッキーで動いている例

#include    <stdio.h>
void f1(int x)
{
    if(x & 1 == 1){ //ラッキー
        printf("成立\n");
    }else{
        printf("不成立\n");
    }
}

if(x & 1 == 1){  //コンパイラはこう解釈する

if(x & (1 == 1)){ // &より==のほうが結合力が強い

if(x & (真)){   // (1==1)は真

if(x & (1)){   //真は1

if(x & 1){

上記のようにコンパイラは解釈するので
結果としてプログラマの意図したとおり動きます。


■2.ビット演算子の結合力で失敗した例

void f2(int x)
{
    if(x & 2 == 2){//★ダメ
        printf("成立\n");
    }else{
        printf("不成立\n");
    }
}

しかしif(x & 2 == 2){は
プログラマの意図したとおりには動きません。

if(x & 2 == 2){をコンパイラはこう解釈する

if(x & (2 == 2)){ // &より==のほうが結合力が強い

if(x & (真)){   // (2==2)は真

if(x & (1)){   //真は1

if(x & 1){
と解釈するので結果としてプログラマの意図したとおり動きません。

※2bit目を確認したかったのに1bit目を確認しています。


■3.カッコで結合力を明確にした修正例

void f3(int x)
{
    if((x & 2) == 2){//OK!
        printf("成立\n");
    }else{
        printf("不成立\n");
    }
}

&、|、^ビット演算子の結合力は直観と異なります
【演算子の優先度と結合規則】の表を暗記しなくてもよいので
ビット演算子の回りに丸カッコを付ける習慣をつけましょう

■4.if(変数|非ゼロ定数)は常に真

(warning)
Result of operator ‘|’ is always true if one operand is non-zero.
Did you intend to use ‘&’?

警告:’|‘演算子ではなくて’&‘演算子では?[(warning)badBitmaskCheck]

int f(int x) {
    if(x|3) //NG if(変数|非ゼロ定数)
        return  1;
    return  0;
}

xの値に無関係に(x|3)の演算結果は非ゼロとなります。

if(x|3)

if(非ゼロ)

if(真)

if文は常に成り立ちます。


■5.bool変数はビット演算に通常使用しない

(style)
Boolean variable ‘b’ is used in bitwise operation. Did you mean ‘&&’?

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

#include    <stdbool.h>
bool    f(bool b,unsigned int x)
{
    if(b & 4U){//NG
        return  1;
    }
    if(b & x){//NG
        return  1;
    }
    return  0;
}

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

if(b & x)も同様。&と&&を間違えた可能性があります。

参考:

EXP00-C. 括弧を使用して演算の優先順位を指定する

https://www.jpcert.or.jp/sc-rules/c-exp00-c.html