【VBA実験】何回NotしてもTrueになるTrueを作る

あけましておめでとうございます。 今年もよろしくお願いいたします。

前書き

私が職場で使っているVBAのライブラリの中には、「何回NotしてもTrueになるTrue」を返すAPIを持つものがあります(一般には使われていないライブラリ)。

この「何回NotしてもTrueになるTrue」をVBAだけで作成する方法の記事となります。
そのため、実際のコードに役立つことはほぼ無いでしょう。

VBAのBoolean周りの動作

本来、VBAのTrueは、16bitの符号付き整数で表すと-1になります(VBAの16進数表現で&HFFFF)。
これを、Not演算子でビット単位で否定すると0&H0000)、すなわちFalseになります。

対して、問題のTrueは16bitの符号付き整数で表すと1&H0001)になっており、これに対してNot演算子を使用すると-2&HFFFE)、0ではないためTrueになります。

コード

以下のコードにあるGetTrueNotTrue()関数の返り値が「何回NotしてもTrueになるTrue」になります。

Private Type intType
    Value As Integer
End Type

Private Type boolType
    Value As Boolean
End Type

Function GetTrueNotTrue() As Boolean
    Dim i As intType
    i.Value = 1
    
    Dim b As boolType
    LSet b = i
    
    Let GetTrueNotTrue = b.Value
    
End Function

コードの解説

普通に数値をBoolean型の変数に代入しても、自動型変換が行われ、VBA本来のTrue・Falseとして代入されてしまいます。
今回は数値のバイナリ表現を保ったまま、Boolean型の変数に代入したいため、別の方法をとる必要がありました。

上記のコードでは、ユーザー定義型のバイナリコピーができるLSetステートメントを使用し、Integer型の1のバイナリ表現をBoolean型にコピーしています。

Private Type intType
    Value As Integer
End Type

Private Type boolType
    Value As Boolean
End Type

で入れ物となるユーザー定義型を定義します (VBAではIntegerもBooleanも2バイトの領域を必要とします)。

    Dim i As intType
    i.Value = 1

でInteger型の1を設定、

    Dim b As boolType
    LSet b = i

で別のユーザー定義型にバイナリコピーしています。

動作の確認

Private Sub Sample()
    Debug.Print GetTrueNotTrue()        '-> True
    Debug.Print Not GetTrueNotTrue()    '-> True
    Debug.Print CInt(GetTrueNotTrue())  '-> 1
End Sub

無事、「何回NotしてもTrueになるTrue」を作成できました。