0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【VBA】知らないとハマるBoolean型の落とし穴(Trueは-1です)

0
Posted at

目次

  1. はじめに
  2. Boolean型の実体は整数型
  3. True が -1 である理由
  4. 比較演算での注意点
  5. 実務での推奨パターン
  6. まとめ

はじめに

VBAで条件分岐を書いていて、Boolean型の変数を数値として扱おうとしたときに予想外の動きをした経験はありませんか。実はTrue-1として扱われるため、この仕様を知らないとバグの原因になることがあります。

Boolean型の実体は整数型

Boolean型は内部的には整数型として保存されています。具体的にはTrue-1False0です。

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-1False0であることが確認できます。

このコードは空白のExcelブックに貼り付けて、そのまま実行できます。VBEのイミディエイトウィンドウ(Ctrl + G)で結果を確認してください。

【なぜ -1 なのか】

他の多くのプログラミング言語ではTrue1として扱われることが多いため、VBAの-1は少し特殊に感じられます。これには歴史的な理由があります。

VBAの元となったBASIC言語では、ビット演算(2進数での計算)との整合性を取るため、すべてのビットが1である状態をTrueとしました。2の補数表現(負の数の表現方法)では、すべてのビットが1の値は-1になります。つまり、ビット演算で「すべて真」を表現するために-1が採用されました。

True が -1 である理由

【ビット表現で考える】

整数をビット(2進数)で表現すると、この仕様の意味がより明確になります。

False(0)は全ビットが0True(-1)は全ビットが1です。16ビットで表現すると、False0000000000000000True1111111111111111となります。

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は、ANDORなどのビット演算と組み合わせやすいという利点があります。

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関数(絶対値を返す関数)を使えば、-11に変換できます。ただし、可読性(読みやすさ)を考えると、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型を使う場合も、TrueFalseを返せば十分です。内部表現を気にする必要はありません。

【唯一注意が必要な場面】

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-1False0として扱われます。通常はBoolean型として扱えば問題ありませんが、数値として扱う場合はAbs関数や条件分岐を使って明示的に変換することで、予期しない動作を防げます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?