Gar*_*eth 59 vba integer integer-overflow long-integer
我经常看到Overflow
与vba错误有关的问题.
我的问题是为什么使用integer
变量声明而不是仅仅定义所有数值变量(不包括double
等)long
?
除非您正在执行类似for循环的操作,您可以保证该值不会超过32,767的限制,否则是否会对性能产生影响或其他会导致不使用long
?
Rub*_*uck 119
整数变量存储为16位(2字节)数字
长(长整数)变量存储为带符号的32位(4字节)数字
因此,好处是减少了内存空间.一个整数占用了一半的内存.现在,我们讨论的是2个字节,所以除非你存储一个TON的整数,否则它不会产生真正的差别.
但是在 32位系统上,16位整数会无声地转换为长整数,而无需使用更大范围的数字.溢出仍然发生,它需要同样多的内存.性能甚至可能受到影响,因为必须转换数据类型(在非常低的级别).
不是我想要的参考,但....
我的理解是底层VB引擎将整数转换为long,即使它被声明为整数.因此,可以注意到轻微的速度降低.我已经相信了一段时间,也许这就是为什么上面的陈述,我没有要求推理.
这是我正在寻找的参考.
简而言之,在32位系统中,2字节整数被转换为4字节长.实际上没有其他方法可以使各个位正确排列以进行任何形式的处理.考虑以下
Run Code Online (Sandbox Code Playgroud)MsgBox Hex(-1) = Hex(65535) ' = True
显然-1不等于65535但计算机正在返回正确答案,即"FFFF"="FFFF"
然而,如果我们强制-1到一个很长的第一个我们会得到正确的答案(65535大于32k自动很长)
Run Code Online (Sandbox Code Playgroud)MsgBox Hex(-1&) = Hex(65535) ' = False
"FFFFFFFF"="FFFF"
通常,VBA在现代系统中声明"As Integer"没有任何意义,除非某些遗留API期望接收整数.
最后我发现了我真正想要的msdn文档.
传统上,VBA程序员使用整数来保存较小的数字,因为它们需要较少的内存.但是,在最近的版本中,VBA将所有整数值转换为Long类型,即使它们被声明为Integer类型.因此,使用Integer变量不再具有性能优势; 实际上,Long变量可能会稍快一些,因为VBA不必转换它们.
因此,总而言之,现在几乎没有理由使用某种Integer
类型.除非你需要使用期望16位int的旧API调用Interop.
值得指出的一点是,一些旧的API函数可能需要16位(2字节)整数的参数,如果你是32位并尝试传递一个整数(已经是4字节长)通过引用,由于字节长度的不同,它将无法工作.
感谢Vba4All指出了这一点.
Pat*_*ick 12
正如其他答案所述,int和long之间的真正区别在于其内存空间的大小,因此也就是它可以容纳的数量的大小.
这里是这些数据类型的完整文档 http://msdn.microsoft.com/en-us/library/office/ms474284(v=office.14).aspx
一个整数是16位,并且可以表示-32,768和32768之间的值
a long是32位,可以表示-2,147,483,648到2,147,483,648
并且有一个64位的LongLong,可以像9个pentilion一样处理
要记住的最重要的事情之一是数据类型因语言和操作系统/平台而异.在您的VBA世界中,长度为32位,但在64位处理器的c#中,长度为64位.这可能会引起很大的混乱.
虽然VBA不支持它,但当您转移到.net或java或其他语言中的任何其他语言时,我更喜欢使用int16,int32和int64的系统数据类型,这使我能够更加透明地了解这些值.可以保存在这些数据类型中.
尽管这篇文章已有四年历史,但我对此很好奇,并进行了一些测试.最重要的是要注意编码器应该始终将变量声明为SOMETHING.未申报的变量显然表现最差(技术上未申报Variant
)
Long
确实表现最快,所以我不得不认为微软总是建议使用Long
而不是Integer
有意义.我猜测也是如此Byte
,但大多数程序员都没有使用它.
64位WINDOWS 10 LAPTOP的结果
使用代码:
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
Run Code Online (Sandbox Code Playgroud)
这是一个空间与必要性的问题。
在某些情况下,有必要使用long。如果您要循环遍历大型 Excel 文件中的行,则保存行号的变量应该是 long。
但是,有时您会知道整数可以解决您的问题,而使用 long 会浪费空间(内存)。单个变量确实没有多大区别,但是当您开始处理数组时,它就会产生很大的区别。
在VBA7中,整数为2个字节,长整型为4个字节
如果您有一个包含 1 到 10 之间的 100 万个数字的数组,则使用整数数组将占用大约2MB 的 RAM,而长数组大约需要 4MB 的 RAM。
小智 5
我采用了@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
Run Code Online (Sandbox Code Playgroud)