为什么要使用整数而不是长整数?

7 浏览
0 Comments

为什么要使用整数而不是长整数?

我经常看到关于 vbaOverflow 错误的问题。

我的问题是,为什么要使用 integer 变量声明,而不是将所有数字变量(不包括 double 等)定义为 long 呢?

除非你正在执行像 for 循环这样的操作,可以保证该值不会超过 32,767 的限制,否则是否使用 long 会对性能或其他因素产生影响?

admin 更改状态以发布 2023年5月20日
0
0 Comments

即使这篇文章已经有四年的历史,我还是很好奇并进行了一些测试。最重要的是,程序员应该始终将变量声明为某种类型。未声明的变量性能显然是最差的(未声明的变量在技术上是Variant)。
Long的执行速度最快,所以我认为微软建议始终使用Long而不是Integer是有道理的。我猜Byte也是如此,但大多数程序员不使用它。

在64位Windows 10笔记本电脑上的结果

变量奥林匹克

使用的代码:

Sub VariableOlymics()
'Run this macro as many times as you'd like, with an activesheet ready for data
'in cells B2 to D6
Dim beginTIME As Double, trials As Long, i As Long, p As Long
    trials = 1000000000
    p = 0
    beginTIME = Now
    For i = 1 To trials
        Call boomBYTE
    Next i
    Call Finished(p, Now - beginTIME, CDbl(trials))
    p = p + 1
    beginTIME = Now
    For i = 1 To trials
        Call boomINTEGER
    Next i
    Call Finished(p, Now - beginTIME, CDbl(trials))
    p = p + 1
    beginTIME = Now
    For i = 1 To trials
        Call boomLONG
    Next i
    Call Finished(p, Now - beginTIME, CDbl(trials))
    p = p + 1
    beginTIME = Now
    For i = 1 To trials
        Call boomDOUBLE
    Next i
    Call Finished(p, Now - beginTIME, CDbl(trials))
    p = p + 1
    beginTIME = Now
    For i = 1 To trials
        Call boomUNDECLARED
    Next i
    Call Finished(p, Now - beginTIME, CDbl(trials))
    p = p + 1
End Sub
Private Sub boomBYTE()
Dim a As Byte, b As Byte, c As Byte
    a = 1
    b = 1 + a
    c = 1 + b
    c = c + 1
End Sub
Private Sub boomINTEGER()
Dim a As Integer, b As Integer, c As Integer
    a = 1
    b = 1 + a
    c = 1 + b
    c = c + 1
End Sub
Private Sub boomLONG()
Dim a As Long, b As Long, c As Long
    a = 1
    b = 1 + a
    c = 1 + b
    c = c + 1
End Sub
Private Sub boomDOUBLE()
Dim a As Double, b As Double, c As Double
    a = 1
    b = 1 + a
    c = 1 + b
    c = c + 1
End Sub
Private Sub boomUNDECLARED()
    a = 1
    b = 1 + a
    c = 1 + b
    c = c + 1
End Sub
Private Sub Finished(i As Long, timeUSED As Double, trials As Double)
    With Range("B2").Offset(i, 0)
            .Value = .Value + trials
            .Offset(0, 1).Value = .Offset(0, 1).Value + timeUSED
            .Offset(0, 2).FormulaR1C1 = "=ROUND(RC[-1]*3600*24,0)"
    End With
End Sub

0
0 Comments

整数变量以16位(2字节)数字存储,长(长整数)变量以带符号的32位(4字节)数字存储。因此,好处在于减少内存空间。整数占用的内存空间是长整数的一半。现在,我们说的是2字节,因此对于单个整数来说不会产生实际影响,只有在处理大量整数(例如大型数组)且内存使用率关键时才需要考虑。

但是,在32位系统上,减半的内存使用会带来性能成本。当处理16位整数(例如递增循环计数器)进行某些运算时,处理器会将值默默地转换为一个临时的Long,而没有较大的数值范围的好处。溢出仍然会发生,并且处理器用于存储计算值的寄存器将以任何方式占用相同的内存(32位)。甚至会因为数据类型必须在非常低的级别上进行转换而受到性能影响。我的理解是,即使声明为整数,底层VB引擎仍将整数转换为长整数。因此,可以注意到轻微的速度降低。我已经相信了很长时间,也许这也是为什么上面的声明被作出的原因,我没有问过原因。
来自ozgrid论坛
这是我正在寻找的参考资料。
简短的答案是,在32位系统中,2字节整数转换为4字节longs。实际上没有其他方法可以使各自的位正确地对齐以进行任何形式的处理。请考虑以下内容

MsgBox Hex(-1) = Hex(65535) ' = True

显然,-1不等于65535,但计算机返回了正确的答案,即"FFFF" = "FFFF"
如果我们首先将-1强制转换为long,则会得到正确的答案(65535大于32k,自动是long)

MsgBox Hex(-1&) = Hex(65535) ' = False

"FFFFFFFF" = "FFFF"

通常,在现代系统中,在VBA中声明"As Integer"没有意义,除非是一些旧的API希望接收一个整数。
来自pcreview论坛
最终我找到了msdn文档。传统上,VBA程序员使用整数来存储小数值,因为它们需要更少的内存。然而,在最近的版本中,VBA将所有整数值转换为类型Long,即使它们被声明为类型Integer。因此,使用Integer变量不再具有性能优势;事实上,Long变量可能会稍微快一些,因为VBA不需要将其转换。

为了澄清评论:整数仍然需要更少的内存来存储-一个大的整数数组将需要比具有相同维度的Long数组少很多RAM(在任务管理器中可以自行检查,几乎是准确的减半)。但是,由于处理器需要处理32位内存块,因此当它执行计算时,VBA会暂时将整数转换为长整数。

因此,总结一下,现在几乎没有什么好的理由使用Integer类型了。除非你需要与期望16位整数的旧API调用进行Interop,或者你正在使用大量的小整数数组并且内存很紧张。

值得指出的一件事是,一些旧的API函数可能正在期望16位(2字节)整数作为参数,如果你正在32位上尝试通过引用传递一个整数(已经是4字节长的整数),由于字节长度的差异,它将无法正常工作。

感谢Vba4All指出这一点。

0