我经常会在vba看到与Overflow
错误相关的问题。
我的问题是为什么使用integer
变量声明而不只是将所有数值变量(double
等除外)定义为long
?
除非您执行类似for循环的操作,否则您可以保证该值不会超过32,767的限制,是否会影响性能或其他不会使用long
的内容?
答案 0 :(得分:113)
整数变量存储为16位(2字节)数字
长(长整数)变量存储为带符号的32位(4字节)数字
因此,好处是减少了内存空间。一个整数占用了一半的内存。现在,我们讨论的是2个字节,所以除非你存储一个整数的TON,否则它不会产生真正的区别。
32 位系统上的但 ,16位整数会以无声方式静默转换为长整数可以使用更大范围的数字。溢出仍然发生,它需要同样多的内存。 Performance may even be hurt因为必须转换数据类型(在非常低的级别)。
不是我要找的参考,但....
我的理解是底层VB引擎将整数转换为long,即使它被声明为整数。因此,可以注意到轻微的速度降低。我已经相信了一段时间,也许这就是为什么上面的陈述,我没有要求推理。
这是我要找的参考资料。
简短回答,在32位系统中,2字节整数被转换为4字节 多头。实际上没有其他方法可以使各个位正确排列 任何形式的处理。请考虑以下
MsgBox Hex(-1) = Hex(65535) ' = True
显然-1不等于65535但计算机正在返回正确的值 回答,即 " FFFF" =" FFFF"
然而,如果我们强制将-1推向第一,我们就会得到正确的 回答(65535大于32k自动长)
MsgBox Hex(-1&) = Hex(65535) ' = False
" FFFFFFFF" =" FFFF"
一般来说,VBA没有必要声明" As Integer"在现代 系统,除了一些预期会收到的遗留API之外 整数。
最后我发现msdn documentation我真的真的在寻找。
传统上,VBA程序员使用整数来保持小 数字,因为他们需要更少的内存。在最近的版本中, 但是,VBA会将所有整数值转换为Long类型,即使它们是“re” 声明为Integer类型。因此,不再具有性能优势 使用整数变量;实际上,Long变量可能略有不同 更快,因为VBA不必转换它们。
因此,总而言之,现在几乎没有理由使用Integer
类型。 除非 ,否则需要使用期望16位int的旧API调用进行Interop。
有一点值得指出的是,一些旧的API函数可能期望16位(2字节)整数的参数,如果你是32位并试图传递整数(已经是4)通过引用它将无法工作,因为字节长度不同。
感谢Vba4All指出这一点。
答案 1 :(得分:11)
正如其他答案所述,int和long之间的真正区别在于其内存空间的大小,因此也就是它可以容纳的数字的大小。
这是有关这些数据类型的完整文档 http://msdn.microsoft.com/en-us/library/office/ms474284(v=office.14).aspx
整数是16位,可以表示介于-32,768和32,767之间的值
长是32位,可以代表-2,147,483,648到2,147,483,647
并且有一个 LongLong ,这是64位,可以处理像9 pentilion
要记住的最重要的事情之一是数据类型因语言和操作系统/平台而异。在您的VBA世界中,长度为32位,但在64位处理器的c#中,长度为64位。这可能会引起很大的混淆。
虽然VBA不支持它,但当您转移到.net或java或其他语言中的任何其他语言时,我更喜欢使用 int16 , int32 <的系统数据类型/ strong>和 int64 ,这使我对这些数据类型中可以保存的值更加透明。
答案 2 :(得分:7)
VBA有很多历史包袱。
一个Integer
是16位宽,当16位架构/字大小普遍时,它是一个很好的默认数字类型。
Long
为32位宽,应尽可能使用(IMO)。
答案 3 :(得分:6)
即使这篇文章已有四岁了,我对此还是很好奇,并进行了一些测试。需要注意的最重要的一点是,编码人员应 始终将变量声明为SOMETHING 。未声明的变量显然表现最差(技术上未声明为Variant
)
Long
的执行速度最快,所以我认为Microsoft的建议始终使用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
答案 4 :(得分:4)
这是空间 vs 必要性问题。
在某些情况下使用长按必需。如果您循环遍历大型Excel文件中的行,则保存行号的变量应该很长。
但是,有时你会知道一个整数可以处理你的问题而使用一个长整数会浪费空间(内存)。个别变量确实没有多大区别,但是当你开始处理数组时,它可以产生很大的不同。
在VBA7中,整数是2个字节,长整数是4个字节
如果您有一个介于1和10之间的100万个数字的数组,则使用整数数组将占用约 2MB的RAM,而长数组的RAM大约为4MB。
答案 5 :(得分:1)
我采用了@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
答案 6 :(得分:0)
正如其他人已经提到的,长 占用的空间可能是 Integer 的两倍。正如其他人已经提到的那样,除非您要处理额外的超大量数据,否则,当前计算机的高容量意味着您将不会看到任何性能上的差异:
考虑到 1百万个值,对于每个值,使用整数和长整型之间的差为2个字节,因此2 * 1 000 000 / 1,024 / 1024 = 小于2您的RAM中的差异为MB ,这可能远远小于RAM容量的1%甚至0.1%。
考虑到PGSystemTester所做的基准测试,当处理100亿个批处理(共4个操作)时,Long和Integer之间相差811-745 = 66秒。将数量减少到 100万次操作,我们可以预期66/10000/4 = 执行时间差异小于2ms。
我个人使用Integers和Longs来帮助提高代码的可读性,尤其是在循环中,其中Integer表示循环应该很小(小于1000次迭代),而Long告诉我该循环预计会很大(超过1000个)。
请注意,此主观阈值远低于整数上限,我使用Longs只是为了区分自己的大小定义。
答案 7 :(得分:-7)
也许CS毕业可以更好地解释它,但是整数需要更少的内存来存储(可能与非常简单的VBA脚本无关)。
它还保证/验证变量将始终为整数(非小数)。我很确定如果你将6.7存储为整数,它将在VBA中转换为数字7。
执行此操作可能不是最佳做法,但可能存在需要这样做的情况。我认为主要目的是数据验证/完整性。特别是,对于需要发生某些事情的循环是的,X次 - 小数没有意义。
主要区别在于内存 - 如果我记得长是64位而整数是32位。