我经常看到与Overflow
错误有关的问题vba。
我的问题是为什么使用integer
变量声明而不是仅将所有数字变量(不包括double
等)定义为long
?
除非您要执行for循环之类的操作,否则您可以保证该值不会超过32,767的限制,那么这是否会对性能产生影响或导致其他原因导致不使用long
?
Answers:
整数变量存储为16位(2字节)数字
长(长整数)变量存储为带符号的32位(4字节)数字
因此,好处是减少了存储空间。整数占用Long内存的一半。现在,我们谈论的是2个字节,因此它不会对单个整数产生真正的影响,仅当您处理整数TONS(例如大型数组)并且内存使用至关重要时,才需要担心。
但是在32位系统上,将一半的内存使用量以性能为代价。当处理器实际使用16位整数执行某些计算时(例如,增加循环计数器),该值将无提示地转换为临时Long,而没有使用更大范围的数字的好处。仍然会发生溢出,并且处理器用来存储计算值的寄存器将以相同的方式占用相同数量的内存(32位)。性能甚至可能会受到损害,因为必须转换数据类型(非常低的级别)。
不是我要找的参考,而是...。
我的理解是,底层的VB引擎即使将整数声明为整数,也会将整数转换为long。因此,可以注意到速度略有下降。我已经相信了一段时间,也许这也是为什么做出上述声明的原因,我没有要求推理。
这是我一直在寻找的参考。
简短的回答,在32位系统中,将2个字节的整数转换为4个字节的Longs。确实没有其他方法可以使各个位正确排列以进行任何形式的处理。考虑以下
MsgBox Hex(-1) = Hex(65535) ' = True
显然-1不等于65535,但是计算机正在返回正确的答案,即“ FFFF” =“ FFFF”
但是,如果我们首先将-1强制设为长,我们将得到正确的答案(65535大于32k会自动很长)
MsgBox Hex(-1&) = Hex(65535) ' = False
“ FFFFFFFF” =“ FFFF”
通常,在VBA中没有必要在现代系统中将“ As Integer”声明为“ As Integer”,也许某些预期会收到Integer的旧式API除外。
最后,我找到了我真正想要的msdn文档。
传统上,VBA程序员使用整数来保存小数字,因为它们需要较少的内存。但是,在最新版本中,VBA会将所有整数值转换为Long类型,即使它们被声明为Integer类型也是如此。因此,使用Integer变量不再具有性能优势。实际上,长变量可能会稍快一些,因为VBA不必转换它们。
根据注释进行说明:整数仍然需要较少的内存来存储-与相同尺寸的Long数组相比,大型整数数组所需的RAM要少得多。但是由于处理器需要处理32位内存块,因此VBA在执行计算时会暂时将Integers转换为Longs
因此,总而言之,Integer
这些天几乎没有充分的理由使用类型。除非您需要使用期望16位int的旧API调用进行Interop,否则除非您使用的是小整数的大型数组,并且内存非常宝贵。
值得指出的一件事是,一些旧的API函数可能期望使用16位(2字节)整数的参数,如果您使用的是32位并尝试传递整数(已经是4字节长),作为参考,由于字节长度的不同,它将不起作用。
感谢Vba4All指出这一点。
Integer
是在声明时Type
,类型的布局和大小很重要,这是因为要将类型传递给API,或者是要对文件进行序列化/反序列化,或者是使用LSet
/ Rset
。
Integer
内部进行了内部处理Long
,但出于所有可观察的目的,它Integer
仍然占用两个字节。请参阅stackoverflow.com/q/26717148/11683下的答案和评论,以进行详细讨论。
the msdn documentation I was really truly looking for.
但是,我的评论主要是针对未来的读者不是你自己,因为你已经参加的其他问题,即使你在我看来,答案应该不会被接受(这个我认为应该是)。
正如在其他答案中指出的那样,int和long之间的真正区别是其存储空间的大小,因此也可以容纳数字的大小。
这是有关这些数据类型的完整文档,http://msdn.microsoft.com/zh-cn/library/office/ms474284( v = office.14).aspx
一个整数是16位,并且可以表示-32,768和32767之间的值
一个长是32位,并且可以表示为-2147483648〜2,147,483,647
还有一个长64位的LongLong,可以处理9个摆角
要记住的最重要的事情之一是,数据类型因语言和操作系统/平台而异。在您的VBA环境中,long是32位,但是在64位处理器上的c#中,long是64位。这可能会引起很大的混乱。
尽管VBA不支持它,但是当您移至.net或Java或其他语言时,我更喜欢使用int16,int32和int64的系统数据类型,这使我可以更加透明地了解可以保留在这些数据类型中。
即使这篇文章已有四岁了,我对此还是很好奇,并进行了一些测试。需要注意的最重要的事情是,编码人员应始终将变量声明为SOMETHING。未声明的变量显然表现最差(技术上未声明Variant
)
Long
确实执行速度最快,所以我必须认为,Microsoft的建议始终使用Long
而不是Integer
合理。我猜想与true相同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
Dim a as Variant, b as Variant, c As Variant
应该给出与完全不“变暗”相同的结果。
这是空间与必要性的问题。
在某些情况下,有必要使用很长的时间。如果要遍历大型excel文件中的行,则保存行号的变量应该很长。
但是,有时您会知道整数可以解决您的问题,而使用long会浪费空间(内存)。各个变量实际上并没有多大区别,但是当您开始处理数组时,它可能会有很大的不同。
在VBA7中,整数是2个字节,而long是4个字节
如果您有一个1到10之间的一百万个数字的数组,则使用整数数组将占用大约2MB的RAM,而长数组则需要大约4MB的RAM。
我已经采用@PGSystemTester的方法并对其进行了更新,以消除一些潜在的可变性。通过将循环放入例程中,可以减少调用例程所花费的时间(这是很多时间)。我还关闭了屏幕更新功能,以消除可能造成的任何延迟。
Long
仍然表现最佳,并且由于这些结果仅局限于变量类型的影响,因此变化的幅度值得注意。
我的结果(桌面,Windows 7,Excel 2010):
使用的代码:
Option Explicit
Sub VariableOlympics()
'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
Dim chosenWorksheet As Worksheet
Set chosenWorksheet = ThisWorkbook.Sheets("TimeTrialInfo")
Application.EnableEvents = False
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
trials = 1000000000 ' 1,000,000,000 - not 10,000,000,000 as used by @PGSystemTester
p = 0
beginTIME = Now
boomBYTE trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomINTEGER trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomLONG trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomDOUBLE trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
beginTIME = Now
boomUNDECLARED trials
Finished p, Now - beginTIME, CDbl(trials), chosenWorksheet.Range("B2")
p = p + 1
Application.EnableEvents = True
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
chosenWorksheet.Calculate
End Sub
Private Sub boomBYTE(numTrials As Long)
Dim a As Byte, b As Byte, c As Byte
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomINTEGER(numTrials As Long)
Dim a As Integer, b As Integer, c As Integer
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomLONG(numTrials As Long)
Dim a As Long, b As Long, c As Long
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomDOUBLE(numTrials As Long)
Dim a As Double, b As Double, c As Double
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub boomUNDECLARED(numTrials As Long)
Dim a As Variant, b As Variant, c As Variant
Dim i As Long
For i = 1 To numTrials
a = 1
b = 1 + a
c = 1 + b
c = c + 1
Next i
End Sub
Private Sub Finished(i As Long, timeUSED As Double, trials As Double, initialCell As Range)
With initialCell.Offset(i, 0)
.Value = trials
.Offset(0, 1).Value = timeUSED
.Offset(0, 2).FormulaR1C1 = "=ROUND(RC[-1]*3600*24,2)"
End With
End Sub
正如其他人已经提到的,长期 可能需要两倍的空间作为一个整数。正如其他人已经提到的那样,当前计算机的高容量意味着您将不会在性能上有任何区别,除非您要处理额外的额外大量数据:
考虑一百万个值,对于每个值,使用整数与长整型之间的差异将为2个字节,因此2 * 1 000 000 / 1,024 / 1024 = RAM中的差异小于2 MB,这可能远远小于您的RAM容量的1%甚至0.1%。
考虑到PGSystemTester所做的基准测试,当处理100亿个批次的4个操作时,Long和Integer之间的差异为811-745 = 66秒。将操作数减少到一百万,我们可以预期执行时间的差异为66/10 000/4 =小于2毫秒。
我个人使用Integers和Longs来提高代码的可读性,特别是在循环中,其中Integer表示循环应该很小(少于1000次迭代),而Long告诉我循环应该很大(更多)。超过1000)。
请注意,此主观阈值远低于整数上限,我使用Longs只是为了区分我自己的大小定义。