【C言語】
&演算子と&&演算子の違いは
ビット演算と論理演算の違い

&演算子 違いは短絡評価 &&演算子

■ビット演算と論理演算の違い

#include <stdio.h>
int main(void){
    int bit =  0xFF00 & 0xFF; //⇒ 0x00=ゼロ=偽
    if(bit)  {
        printf("真:%x\n",bit);
    } else {
        printf("偽:%x\n",bit);
    }  
    
    int log = 0xFF00 && 0xFF; //⇒ 非ゼロ&&非ゼロ=真&&真=真 
    if(log)  {
        printf("真:%x\n",log);
    } else {
        printf("偽:%x\n",log);
    }  
}

●ビット演算
0xFF00 & 0xFF

0x00

ゼロ


●論理演算
0xFF00 && 0xFF

非ゼロ&&非ゼロ

真&&真

●実行結果

./a.out
偽:0
真:1

短絡評価は、ビット演算無し論理演算有り

#include <stdio.h>
#include <stdbool.h>
bool    True(void){ 
    printf("%s⇒",__func__); 
    return  true;   
}
bool    False(void){
    printf("%s⇒",__func__); 
    return  false;  
}
int main(void){
    if(False() & True())    puts("結果⇒真");
    else                    puts("結果⇒偽");
      
    if(False() && True())   puts("結果⇒真");
    else                    puts("結果⇒偽");
}

●False() & True()

&はビット演算子なので両辺を簡略化すると
0&1=0=偽となり
if(偽)は成立しないのでelse節 が表示される。

●False() && True()

&&は論理演算子なので両辺を簡略化すると
0&&1=ゼロ&&非ゼロ=偽&&真=偽となる。

第一条件が成立しなかった時点で、
この条件式全体が成立しない事が確定するので
第二条件を評価する必要がない
すなわちTrue()関数は呼ばれない。

これを短絡評価(ショートサーキット動作)と
言う。


●実行結果

./a.out
False⇒True⇒結果⇒偽
False⇒結果⇒偽

Segmentation fault (コアダンプ)するかも

#include <stdio.h>
void bit_and(char  *p){
    printf("%s⇒",__func__);
    if ((p != NULL) & (p[0] != '\0'))   //ビット演算子 
        puts(p) ; 
    else
        puts("nop");
} 
void log_and(char  *p){
    printf("%s⇒",__func__);
    if ((p != NULL) && (p[0] != '\0'))  //論理演算子   
        puts(p) ; 
    else
        puts("nop");
} 
int main(void){
    log_and("ABC");
    log_and(NULL);
    bit_and("DEF");
    bit_and(NULL);
}

論理演算&&を使用すべきところで
ビット演算&を使用して
短絡評価が行われずコアダンプしてしまう例です。

●実行結果

./a.out
log_and⇒ABC
log_and⇒nop
bit_and⇒DEF
Segmentation fault (コアダンプ)

未定義動作なのでコアダンプするとは限りませんが。。。。


ビット単位のOR演算子【|】と 論理OR演算子【||】の違い

#include <stdio.h>
int main(void){
    /*
        0xFF00
        0x00ff
    ------
        0xFFff
    */
    printf("ビット演算  %x\n",0xFF00 |  0xFF);
    
    /*
        0xFF00||0xFF
        ⇒非ゼロ||非ゼロ
        ⇒真||真
        ⇒真
        ⇒1
    */
    printf("論理演算    %x\n",0xFF00 || 0xFF);
}

●実行結果

./a.out
ビット演算  ffff
論理演算    1

■短絡評価有無の違い

#include    <stdio.h>
#include    <stdbool.h>
bool Ltrue(void){
    printf("左⇒");
    return  true ;  
}
bool Rfalse(void) {   
    printf("右⇒");
    return  false ; 
}
int main(void){
    //ビット演算
    if(Ltrue() | Rfalse())  puts("両辺実行");
    else                    puts("来ない");   
    
    //論理演算
    if(Ltrue() || Rfalse()) puts("左辺のみ実行");
    else                    puts("来ない");
}

●Ltrue() | Rfalse() 

|はビット演算子なので
両辺の関数は必ず呼ばれる(評価される)
1|0=1=真なのでthen節が表示される。

●Ltrue() || Rfalse()

||は論理演算子なのでLtrue()が成立した時点でif文は成立する。

このためRfalse()を呼ぶ必要が無い
(Rfalse()を評価する必要が無い)

●実行結果

./a.out
左⇒右⇒両辺実行
左⇒左辺のみ実行

参考:

EXP02-C. 論理 AND 演算子および論理 OR 演算子のショートサーキット動作について注意する