最終更新日 2025年11月18日
■この記事の概要
この記事では、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);
}
}
./a.out
偽:0
真:1●ビット演算
0xFF00 & 0xFF
↓
0x00
↓
ゼロ
↓
偽
●論理演算
0xFF00 && 0xFF
↓
非ゼロ&&非ゼロ
↓
真&&真
↓
真
■短絡評価は、ビット演算無し論理演算有り
#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("結果⇒偽");
}./a.out
False⇒True⇒結果⇒偽
False⇒結果⇒偽●False() & True()
&はビット演算子なので両辺を簡略化すると
0&1=0=偽となり
if(偽)は成立しないのでelse節 が表示される。
●False() && True()
&&は論理演算子なので両辺を簡略化すると
0&&1=ゼロ&&非ゼロ=偽&&真=偽となる。
第一条件が成立しなかった時点で、
この条件式全体が成立しない事が確定するので
第二条件を評価する必要がない
すなわちTrue()関数は呼ばれない。
これを短絡評価(ショートサーキット動作)と
言う。
■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("来ない");
}./a.out
左⇒右⇒両辺実行
左⇒左辺のみ実行