为什么使用整数而不是Long?


68

我经常看到与Overflow错误有关的问题

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

除非您要执行for循环之类的操作,否则您可以保证该值不会超过32,767的限制,那么这是否会对性能产生影响或导致其他原因导致不使用long

Answers:


128

整数变量存储为16位(2字节)数字

Office VBA参考

长(长整数)变量存储为带符号的32位(4字节)数字

Office VBA参考

因此,好处是减少了存储空间。整数占用Long内存的一半。现在,我们谈论的是2个字节,因此它不会对单个整数产生真正的影响,仅当您处理整数TONS(例如大型数组)并且内存使用至关重要时,才需要担心。

但是32位系统上,将一半的内存使用量以性能为代价。当处理器实际使用16位整数执行某些计算时(例如,增加循环计数器),该值将无提示地转换为临时Long,而没有使用更大范围的数字的好处。仍然会发生溢出,并且处理器用来存储计算值的寄存器将以相同的方式占用相同数量的内存(32位)。性能甚至可能会受到损害,因为必须转换数据类型(非常低的级别)。

不是我要找的参考,而是...。

我的理解是,底层的VB引擎即使将整数声明为整数,也会将整数转换为long。因此,可以注意到速度略有下降。我已经相信了一段时间,也许这也是为什么做出上述声明的原因,我没有要求推理。

ozgrid论坛

这是我一直在寻找的参考。

简短的回答,在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除外。

pcreview论坛

最后,我找到了我真正想要的msdn文档

传统上,VBA程序员使用整数来保存小数字,因为它们需要较少的内存。但是,在最新版本中,VBA会将所有整数值转换为Long类型,即使它们被声明为Integer类型也是如此。因此,使用Integer变量不再具有性能优势。实际上,长变量可能会稍快一些,因为VBA不必转换它们。

根据注释进行说明:整数仍然需要较少的内存来存储-与相同尺寸的Long数组相比,大型整数数组所需的RAM要少得多。但是由于处理器需要处理32位内存块,因此VBA在执行计算时会暂时将Integers转换为Longs


因此,总而言之,Integer这些天几乎没有充分的理由使用类型。除非您需要使用期望16位int的旧API调用进行Interop,否则除非您使用的是小整数的大型数组,并且内存非常宝贵。

值得指出的一件事是,一些旧的API函数可能期望使用16位(2字节)整数的参数,如果您使用的是32位并尝试传递整数(已经是4字节长),作为参考,由于字节长度的不同,它将不起作用。

感谢Vba4All指出这一点。


6
值得指出的一件事是,一些旧的API函数可能期望使用16位(2字节)整数的参数,如果您使用的是32位并尝试传递整数(已经是4字节长),作为参考,由于字节长度的不同,它将不起作用。

3
@这是我不明白的意思。如果将Long by ref传递给期望使用ref的Integer的函数,它将使用前两个字节,并且由于数字存储在little-endian中,因此它将起作用(假设只有两个较低的字节才有意义,但是如果此Long仅仅是一个以32位存储的Integer,则很有可能。

3
另一个必须使用的时间Integer是在声明时Type,类型的布局和大小很重要,这是因为要将类型传递给API,或者是要对文件进行序列化/反序列化,或者是使用LSet/ Rset
ThunderFrame

1
该MSDN文章是错误的和/或误导的。它可能表示s在处理器Integer内部进行了内部处理Long,但出于所有可观察的目的,它Integer仍然占用两个字节。请参阅stackoverflow.com/q/26717148/11683下的答案和评论,以进行详细讨论。
Gserg '17

1
您似乎并未在答案中的任何地方声明msdn.microsoft.com/en-us/library/office/…可能是错误的或误导性的,而是将其呈现为。the msdn documentation I was really truly looking for.但是,我的评论主要是针对未来的读者不是你自己,因为你已经参加的其他问题,即使你在我看来,答案应该不会被接受(这个我认为应该是)。
Gserg '17

13

正如在其他答案中指出的那样,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或其他语言时,我更喜欢使用int16int32int64的系统数据类型,这使我可以更加透明地了解可以保留在这些数据类型中。


9

即使这篇文章已有四岁了,我对此还是很好奇,并进行了一些测试。需要注意的最重要的事情是,编码人员应始终将变量声明为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

1
未声明的变量是一个变体。Dim a as Variant, b as Variant, c As Variant应该给出与完全不“变暗”相同的结果。
Vityata

@Vityata,我知道“未声明”表示变体,但请记住,整个讨论的背景是尽管定义了定义,Microsoft仍会自动将整数转换为Long!因此,我不确定在未定义整数的情况下会发生什么。看到结果后,似乎很可能确实是Variants,但这就是为什么我给名称起“ Undeclared”和“ Variant”。此外,这对于低级编码人员可能更有用。但是,我继续进行补充现在就可以了。谢谢您的反馈
。– PGSystemTester

@PGCodeRider-用c ++创建一个dll库并将其添加到VBA并在那里进行基准测试可能会很有趣。结果可能会很有趣。我做了类似的东西在这里- vitoshacademy.com/...
Vityata

8

VBA有很多历史包g。

AnInteger为16位宽,当流行16位体系结构/字长时,它是一种很好的默认数字类型。

ALong为32位宽,应尽可能使用(IMO)。


4

这是空间必要性的问题。

在某些情况下,有必要使用很长的时间。如果要遍历大型excel文件中的行,则保存行号的变量应该很长。

但是,有时您会知道整数可以解决您的问题,而使用long会浪费空间(内存)。各个变量实际上并没有多大区别,但是当您开始处理数组时,它可能会有很大的不同。

  • 在VBA7中,整数是2个字节,而long是4个字节

  • 如果您有一个1到10之间的一百万个数字的数组,则使用整数数组将占用大约2MB的RAM,而长数组则需要大约4MB的RAM。


1
对于1到10之间的数字数组,可以改用BYTE数组,但我理解您的意思。
ChrisB

这可能在15年前是正确的,但现在答案确实过时了。
Vityata '18

这怎么过时了?大熊猫拥有数百万行的问题(大数据/机器学习),或传输大量数据时的网络问题(例如物理实验)
更改

@Alter-我想您错过了原始问题的重点。查看接受的答案。
Vityata '18

看起来我明白了。同样被接受的答案指出,当它说没有区别时,它是在谈论32位系统。
阿尔特

3

我已经采用@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

谢谢。由于您使用的是我的代码,因此给您打勾。您的总体结果与我的相同...但是我同意这种方法。如果我要再做一次,我会使其更加复杂。
PGSystemTester

1

正如其他人已经提到的,长期 可能需要两倍的空间作为一个整数。正如其他人已经提到的那样,当前计算机的高容量意味着您将不会在性能上有任何区别,除非您要处理额外的额外大量数据:

记忆

考虑一百万个值,对于每个值,使用整数与长整型之间的差异将为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只是为了区分我自己的大小定义。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.