目次
はじめに
VBAで条件分岐を書いていて、Boolean型の変数を数値として扱おうとしたときに予想外の動きをした経験はありませんか。実はTrueは-1として扱われるため、この仕様を知らないとバグの原因になることがあります。
Boolean型の実体は整数型
Boolean型は内部的には整数型として保存されています。具体的にはTrueが-1、Falseが0です。
Sub Boolean型の実体を確認()
Dim flag As Boolean
flag = True
Debug.Print flag ' True と表示
Debug.Print CLng(flag) ' -1 と表示
flag = False
Debug.Print flag ' False と表示
Debug.Print CLng(flag) ' 0 と表示
End Sub
CLng関数でLong型(整数型)に変換すると、Trueは-1、Falseは0であることが確認できます。
このコードは空白のExcelブックに貼り付けて、そのまま実行できます。VBEのイミディエイトウィンドウ(Ctrl + G)で結果を確認してください。
【なぜ -1 なのか】
他の多くのプログラミング言語ではTrueが1として扱われることが多いため、VBAの-1は少し特殊に感じられます。これには歴史的な理由があります。
VBAの元となったBASIC言語では、ビット演算(2進数での計算)との整合性を取るため、すべてのビットが1である状態をTrueとしました。2の補数表現(負の数の表現方法)では、すべてのビットが1の値は-1になります。つまり、ビット演算で「すべて真」を表現するために-1が採用されました。
True が -1 である理由
【ビット表現で考える】
整数をビット(2進数)で表現すると、この仕様の意味がより明確になります。
False(0)は全ビットが0、True(-1)は全ビットが1です。16ビットで表現すると、Falseは0000000000000000、Trueは1111111111111111となります。
Sub NOT演算で確認()
Dim flag As Boolean
flag = False
Debug.Print "NOT False = "; Not flag ' True(-1)
Debug.Print "NOT 0 = "; Not 0 ' -1
End Sub
ビット演算のNOT(すべてのビットを反転)を使うと、0の反転が-1になることが分かります。
2の補数表現について詳しく知りたい方は、以下の記事で解説しています。
【論理演算との相性】
全ビットが1である-1は、ANDやORなどのビット演算と組み合わせやすいという利点があります。
Dim a As Boolean, b As Boolean
a = True
b = False
Debug.Print a And b ' False(0)
Debug.Print a Or b ' True(-1)
比較演算での注意点
Boolean型の実体が-1であることを知らないと、比較演算で混乱することがあります。
【よくある間違い】
Dim flag As Boolean
flag = True
' これは期待通りに動作しない
If flag = 1 Then
Debug.Print "フラグが立っています" ' 実行されない
End If
Trueは-1なので、flag = 1の比較はFalseになります。このコードは期待通りに動作しません。
【Boolean型を数値として使う場合】
もしBoolean型を数値として扱いたい場合は、明示的に変換が必要です。
Dim flag As Boolean
Dim count As Long
flag = True
' 間違った方法
count = count + flag ' count には -1 が加算される
' 正しい方法1: Abs関数で絶対値を取る
count = count + Abs(flag) ' 1 が加算される
' 正しい方法2: IIf関数で明示的に変換
count = count + IIf(flag, 1, 0) ' 1 が加算される
Abs関数(絶対値を返す関数)を使えば、-1を1に変換できます。ただし、可読性(読みやすさ)を考えると、IIf関数で明示的に変換する方が分かりやすいかもしれません。
IIf関数について詳しく知りたい方は、以下の記事で解説しています。
【比較演算の推奨パターン】
Boolean型の比較では、以下のパターンが推奨されます。
Dim flag As Boolean
flag = True
' 推奨: Boolean型として比較
If flag Then
Debug.Print "フラグが立っています"
End If
If flag = True Then
Debug.Print "フラグが立っています"
End If
' 非推奨: 数値として比較
If flag = -1 Then ' 動作するが分かりにくい
Debug.Print "フラグが立っています"
End If
Boolean型はBoolean型として扱い、数値としての実体を意識する必要がある場合のみ明示的に変換するのが安全です。
実務での推奨パターン
実際のコーディングでは、Boolean型の内部表現を意識する必要がある場面は多くありません。以下のパターンを守れば、問題なく使用できます。
【基本的な使い方】
' 条件判定
If flag Then
' 処理
End If
' 否定判定
If Not flag Then
' 処理
End If
' Boolean型同士の比較
If flag1 = flag2 Then
' 処理
End If
【関数の戻り値として使う】
Function データが有効か(value As Variant) As Boolean
If IsEmpty(value) Or IsNull(value) Then
データが有効か = False
Else
データが有効か = True
End If
End Function
関数の戻り値としてBoolean型を使う場合も、TrueかFalseを返せば十分です。内部表現を気にする必要はありません。
【唯一注意が必要な場面】
Boolean型を数値計算に直接使おうとする場合のみ、注意が必要です。
Sub カウント処理の例()
Dim i As Long
Dim trueCount As Long
Dim flags(1 To 5) As Boolean
' 何らかの処理でフラグを設定
flags(1) = True
flags(2) = False
flags(3) = True
flags(4) = True
flags(5) = False
' True の個数を数える
For i = 1 To 5
' 間違った方法
' trueCount = trueCount + flags(i) ' -3 になる
' 正しい方法
If flags(i) Then
trueCount = trueCount + 1
End If
Next i
Debug.Print "Trueの個数: "; trueCount ' 3
End Sub
Boolean型を直接加算すると-1が加算されるため、期待した結果になりません。条件分岐を使って明示的にカウントするのが安全です。
まとめ
VBAのBoolean型は内部的にTrueが-1、Falseが0として扱われます。通常はBoolean型として扱えば問題ありませんが、数値として扱う場合はAbs関数や条件分岐を使って明示的に変換することで、予期しない動作を防げます。