
みなさんこんにちは、ガノー(Twitter:Ganohr)です。
この記事では「&&
や||
などの論理演算子」と「&
や|
などのビット演算子」の違いを把握するために、サンプルコードを用いて解説します。
※ サンプルコードはPHPで記述していますが、JavaScript、Java、C、C#で共通する事項です。
更新履歴
2023/02/17 公開
ビット演算子とは?
‘ビット演算子’(-えんざんし)は、字面の通りビット演算のために用いる演算子です。‘演算子’とは「+
や÷(/
)などの四則演算子などを含め、計算式における項を扱うためのルール」です。
この記事ではビット演算子の中でも「&
」演算子(ビット積演算子)と「|
」(ビット和演算子)を扱います。
その他のビット演算子は以下の記事を参照されてください。
論理演算子とは?
‘論理演算子’(ろんりえんざんし)とは、特にプログラミングにおいて、条件式が真か偽かを判定するための演算子です。
論理演算子のより詳細な解説は以下の記事を参照されてください。

この記事では論理演算子の中でも「&&
」(論理積演算子)と「||
」(論理和演算子)を扱います。
&&と&とandと||と|とorの違い
さて本題ですが、&&
と&
とand
と||
と|
とor
の違いは何でしょうか。
これらの違いは、以下3点に要約されます。
- ビット演算子か論理演算子かの違い
- 優先順位の違い
- 短絡評価を行うか否かの違い
なお、「ビット演算子か論理演算子かの違い」については既に解説済みのため割愛します。
その他2つについて違いを見ていきましょう。
優先順位の違い
演算子には優先順位があることはご存知でしょう。優先順位という言葉がピンと来ない方もいるかも知れませんが、四則演算において「×」(乗算子)と「÷」(除算子)の優先順位は高く、それに比べて「+」(加算子)と「-」(減算子)の優先順位は低いと小学校~中学校までの算数・数学にて習っているはずです。
例として以下の計算をしてみてください。Google検索で「3 + 4 × 5 ÷ 5 - 4 × 3」を計算してみる
3 + 4 × 5 ÷ 5 - 4 × 3
(4 × 5 ÷ 5) … 4
(4 × 3) … 12
∴ 3 + 4 - 12 = -5
誤答例
3 + 4 … 7
7 × 5 … 35
35 ÷ 5 … 7
7 - 4 … 3
3 × 3 … 9
この結果が9ではなく-5であるように、演算子にはそれぞれ優先順位が決まっています。
一般的なプログラミング言語においては、
ビット演算子は論理演算子よりも優先順位が高く、また積演算子(ビット積・論理積)は和演算子(ビット和・論理和)よりも優先順位が高くなっています。
加えてPHPでは「and
」や「or
」などの演算子では「&&
」や「||
」よりも優先順位が引く設定されています。
※ PHPにおける演算子の優先順位は以下を参考にされてください
こうした演算子の優先順位は難解であり、また様々なバグの要因となってきたため留意が必要です。
実用的には「条件式の中ではビット演算子を使わない、andやor演算子を使わない」という制約を付けてプログラムしていきます。
$ng = true and false;
var_dump($ng);
$ok = true && false;
var_dump($ok);
$better = (true && false);
var_dump($better);
bool(true)
bool(false)
bool(false)
解説
$ng
の計算は、実直に読むと「true
且つ false
」は通常であれば「false
」となるはずですが、「PHPのand
演算子は代入演算子(=
)よりも優先順位が低いため、「$ng = true
」の代入結果にfalse
のand
を取る動作をします(その結果を代入しないため無視される)。そのためvar_dump
で$ng
を確認するとtrue
の値になっており、多くのバグの温床になってきました。
2つ目の$ok
は、私達プログラマーが通常想定した通りの挙動を示します。要するに代入演算子よりも&&
演算子は優先順位が高いため、まず&&
演算を行った後、その結果を$ok
へ代入します。$ng
と違い、ちゃんと「true
且つ false
」の結果である「false
」が代入されています。
よりベターなのは代入演算子や各種演算子を利用する際は、優先順位を括弧で定義することです。これなら優先順位によるバグは介入しようがありません。とはいえ、通常問題になるのはビット演算子や三項演算子などであるため、ある程度習熟したメンバー同士で開発できる場合はそこまで厳密に行う必要はありません。
論理演算子とビット演算子の違い:短絡評価を行うか否かの違い
‘短絡評価’(たんらくひょうか)とは、論理演算において、以降を評価する必要のないパターンが指定された場合に、評価を行わずに効率化する仕組みのことです。
「以降を評価する必要のないパターン」とは、具体的には論理積結合においてfalse
が出現した位置以降の判定、及び論理和結合においてtrue
が出現した以降の判定です。
var_dump( false || true || false || true );
var_dump( false || true && false && true );
bool(true)
bool(false)
この条件では、短絡評価され、式の途中で評価が確定します。

では実際に短絡評価が正しく動いているのか確認するコードを用いて、動作を確認してみましょう。
function d($val) {
echo "\t" . var_export($val, true) . PHP_EOL;
return $val;
}
echo "d関数のテスト" . PHP_EOL;
d(false);
d(true);
echo PHP_EOL; var_dump(d(false));
echo PHP_EOL; var_dump(d(true));
d関数のテスト
false
true
false
bool(false)
true
bool(true)
d
関数は、短絡評価を確認するために定義したデバッグ用の関数です。
引数で指定された値を順々に、画面にタブ文字を先頭に付与し、且つ、改行して出力します。
このd関数を用いて、実際に短絡評価を確認しましょう。
echo PHP_EOL; var_dump( d( false ) || d( true ) || d( false ) || d( true ) );
echo PHP_EOL; var_dump( d( false ) || d( true ) && d( false ) && d( true ) );
false
true
bool(true)
false
true
false
bool(false)
実行結果を確認すると、たしかに途中で判定が終わり、残りの判定がスキップされていることが確認できます。
このように「短絡評価をうまく使うことで、パフォーマンス・チューニングに役立つ」ことがわかるでしょう。
これをビット演算子(|
及び&
)に置き換えて実行してみると、より理解がはかどります。
echo PHP_EOL; var_dump( d( false ) | d( true ) | d( false ) | d( true ) );
echo PHP_EOL; var_dump( d( false ) | d( true ) & d( false ) & d( true ) );
false true false true int(1) false true false true int(0)
論理演算子を用いたパフォーマンス・チューニングでは、
- 判定速度が早い条件を前に出す
- 多くの内容を弾ける条件を前に出す
といった観点でプログラミングを行うことで、効率的なコードを作成できます。
ただし、こうした効率化はC言語の時代から引き継がれていますが、最近ではJITコンパイラーの技術革新により、実行時に自動的に最適化されることが多く、あまり意識する必要がなくなってきています。
とはいえ異様に遅いコードがある場合は、見直してみると良いでしょう。
条件式の中では、論理演算子(&&
や||
)のみを用い、ビット演算子の混在や、and
演算子やor
演算子を使用しないようにしましょう
以下のコードを見てください。このd
関数は、文字列で指定された計算を行い、与えられた式とその答えを画面に出力します。
$b = ['false', 'true'];
$ret = null;
function d($s) {
global $b;
global $ret;
echo str_pad($s, 36) . ":";
eval('$ret=(' . $s . ');');
echo " $b[$ret]\n";
}
d("false && false && false || true");
d("false && false && true || false");
d("false && false | true && true");
d("false && false || true && true");
d("false | true | true and false");
d("false | true | false and true");
この12 ~ 17行目に連なる各条件判定の結果が、true
になるかfalse
になるか初見で且つ迅速に判別できるでしょうか?
PHPでは先述の通り|
と||
や&
と&&
や、あまつさえor
にand
の演算子の優先順位それぞれ異なります。
false && false && false || true : true
false && false && true || false : false
false && false | true && true : false
false && false || true && true : true
false | true | true and false : false
false | true | false and true : true
これは極端な例ではありません。
プログラミングを行っていく中では、複数の条件を複雑に組み合わせなければならない例はいくらでもあります。
したがって、条件式では必ず「||
か&&
のみを利用」する必要があります。
また次の節にて解説している「半角丸括弧による条件式の重み付け」を用いることで、簡単に理解しやすいコードを記述するよう気をつけねばなりません。
カッコで条件式の重み付けを明示しよう
先程のコードにおいて、以下の部分を見てください。
d("false && false | true && true");
d("false | true | true and false");
d("false | true | false and true");
これはビット演算子と論理演算子が混在していたり、条件式でありながらビット演算子が利用されているため理解しにくいコードになっています。
加えてビット演算子の優先順位が論理演算子よりも高い点に注意が必要です。
例題として、ビット演算子とand
演算子の使用をやめて、論理演算子(&&
演算子及び||
演算子)のみを使用するようコードを書き換えてみましょう。
その際に活用するのが(
~)
(半角丸括弧)を用いた条件式の重み付けです。
方法は簡単で、優先順位を上げたい項と演算子の組み合わせを半角丸括弧で囲っていくだけです。複数の条件が入れ子になっている場合は、内側から外側に括弧で囲っていきます。
※ ご自身で実践したあと、折りたたまれた内容を展開して答え合わせをしてください。
回答例
d("false && (false || true) && true");
d("((false || true) || true) && false");
d("((false || true) || false) && true");
このように各演算の実行順序の違いは半角丸括弧を用いることで自由に制御できます。
そしてビット演算子の実行順序の違いなどを意識する必要がなくなるため、判定順序が明確になります。
最後に
この記事はプログラミングを行う上で比較的初歩の内容ながら、あまり正しく理解されていない論理演算子(&&
や||
)とビット演算子(&
や|
)の違いを解説しました。
参考になったら、SNSへシェアしたり、ブックマークしてくだされば励みになります。
コメントを書く