将布尔值转换为整数,true返回-1?

45

我正在处理一些使用 VB.NET 的代码,这些代码似乎是通过 CInt(myBoolean) 将布尔值转换为整数。奇怪的是,如果这个值为 true,则返回 -1。例如:

CInt(True)  // returns -1
CInt(False) // returns 0

在其他编程语言中是否也是这样的呢?

我原本认为布尔值表示真时应该是1,假时应该是0。还有,是否有办法让Visual Basic将true赋值为1而不是-1?

11个回答

44

通常,false的值用0表示,true的值用任何非0整数值表示。关于true和false的具体值(以及其他值),你不应该依赖它们——它们可能是特定于实现的。我不确定你试图做什么,但最好不要依赖TrueFalse具有任何特定的整数值,除非你绝对必须这样做。

我能找到的关于VB的具体行为的最好解释来自于Wikipedia:

布尔常量True的数字值为-1。这是因为布尔数据类型存储为16位有符号整数。在此结构中,-1被评估为16个二进制1(布尔值True),而0被评估为16个0(布尔值False)。当对一个16位有符号整数值0执行Not操作时,这一点很明显,它将返回整数值-1,换句话说,True = Not False。当在整数的各个位上执行逻辑操作(如And、Or、Xor和Not)时,这种固有功能变得特别有用。此定义的True也与自20世纪70年代以来Microsoft BASIC实现相关,并且还与当时CPU指令的特性有关。


2
我刚刚测试了这个前提。在VB.NET中,布尔值不等于“-1”,它只等于“1”。我通过使用FieldOffsetAttribute创建具有两个重叠字段的结构来检查这一点。这样,您可以看到布尔值的确切二进制值。CInt只是一种转换。参考旧文档并没有真正帮助我想。 - Martin Mulder
3
我在VB.NET中将True传递给一个接受整数的函数,却得到了值为 -1。在Martjin引用的文章(http://msdn.microsoft.com/en-us/library/ae382yt8.aspx)中,似乎你如何转换布尔值决定了你得到的整数值。 - Brian J

13

您最初使用的一个解决方法是:

 Dim i As Integer = CInt(Int(False))

这将返回0。

 Dim i As Integer = CInt(Int(True))
这将返回1。

3
对我来说不起作用。CInt()返回的是带符号的整数,所以我又得到了-1。也许这是一个旧的解决方案(我使用的是VBA 7.1)。 - AlexL
1
这只发生在VB.NET中,它的原因是Int()函数的行为被悄无声息地更改了。在VB/A中,它返回-1。 - GSerg
@GSerg 如果你注意到12年前的原帖中提到他们正在使用VB.NET而不是VBA。虽然它们相似,但这可能是为什么它对你不起作用的原因。 - Michael Eakins

9
似乎这是一个陷阱,我不知道其他类似的行为例子。 数据类型故障排除(Visual Basic)指定了这种行为,并带有“不要这样做”的备注。请注意下面的内容:
框架中的转换
系统命名空间中Convert类的ToInt32方法将True转换为+1。
如果您必须将布尔值转换为数字数据类型,请小心选择使用哪种转换方法。


5

我曾经遇到过同样的问题,并使用了 Math.Abs 函数处理结果 :)


4
在20世纪70年代和80年代,许多版本的BASIC实现了位运算,并使用它们的AND和OR运算符,并使真实的条件表达式评估为-1(即用于整数的二进制补码中的“所有位设置”值)。我不确定为什么要决定让真实条件表达式评估为所有位设置值;能够使用AND针对条件表达式掩码整数可能比乘法更快,但鉴于解释器的内部机制,差异将很小。
无论如何,微软为PC生产的第一批BASIC版本都遵循了这种真实条件评估为-1(所有位设置)的传统;由于QuickBASIC又被认为与之兼容,Visual Basic也被认为与QuickBASIC兼容,因此它们使用相同的表示形式。虽然.Net将整数和布尔值识别为不同的类型,但VB.Net希望为可能依赖旧行为的VB6程序提供迁移路径。在“Option Strict Off”的情况下,VB.Net将隐式地将True布尔值转换为整数-1;尽管大多数程序员使用“Option Strict On”,但CInt()的行为与隐式转换行为不同将会很困惑。

3
我测试了它并得到了以下结果:
Public Module BooleanTest
Public Function GetTrue() As Boolean
    GetTrue = True
End Function
End Module

...

[StructLayout(LayoutKind.Explicit)]
struct MyStruct
{
    [FieldOffset(0)]
    public bool MyBool;
    [FieldOffset(0)]
    public int MyInt32;
}

static void Main(string[] args)
{
    MyStruct b1, b2;
    b1.MyInt32 = 0;
    b2.MyInt32 = 0;
    b1.MyBool = BooleanTest.BooleanTest.GetTrue();
    b2.MyBool = true;
    Console.WriteLine(b1.MyInt32);
    Console.WriteLine(b2.MyInt32);
}

这将导致:

1
1

我希望这能证明.NET中所有的True值都是相同的。原因很简单:所有.NET成员都必须相互通信。如果object.Equals(trueFromCSharp, trueFromVB)结果为false(就像trueFromCSharp == trueFromVB一样),那将是奇怪的。 CInt只是一个函数,它会将True转换为-1。另一个函数Int将返回1。但这些只是转换器,并不意味着二进制值。

2

我在使用MySQL时遇到了同样的问题,因为它没有布尔类型,只有tinyint(1)。

我的解决方案是编写一个转换函数,以确保在将值插入数据库之前是正确的。

        Public Function BoolToMySql(bVal As Boolean) As Integer
            Dim retVal As Integer
            If bVal = True Then
                retVal = 1
            Else
                retVal = 0
            End If
                 BoolToMySql = retVal
        End Function

1

我希望你能帮助他人在VB.NET中处理布尔值。这是一种更好的编写VB.NET代码的方式,与Roger编写的代码相比。

Public Function BoolToMySql(bVal As Boolean) As Integer
   return  If(bVal, 1, 0)
End Function

1
我认为应该是 IIf,而不是 If....所以:return IIf(bVal, 1, 0) - jbyrd

0

我发现其他答案对我正在处理的VBA特定场景不够完善。这在VB.NET中未经过测试。

我想要在一行代码中将任何不等于0的数字变为1,并将0保持为0,而无需使用If语句。我最终采用的方法是:

Abs(CBool(iCount))

CBool()函数将给定的数字(如上例中的iCount)转换为布尔值,将可能的结果缩小为两个值;值为-1True和值为0False

然后,Abs()函数取布尔值的绝对值(无负数),以返回False0True1

在实践中,以下情况将返回0

Abs(CBool(0))
Abs(False)

并且以下返回1

Abs(CBool(1))
Abs(CBool(-1))
Abs(CBool(-38473))
Abs(CBool(358677))
Abs(True)

我希望这对于其他人在处理类似情况时有所帮助。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接