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

Gar*_*eth 59 vba integer integer-overflow long-integer

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

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

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

Rub*_*uck 119

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

MSDN

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

MSDN

因此,好处是减少了内存空间.一个整数占用了一半的内存.现在,我们讨论的是2个字节,所以除非你存储一个TON的整数,否则它不会产生真正的差别.

但是 32位系统上,16位整数会无声地转换为长整数,而无需使用更大范围的数字.溢出仍然发生,它需要同样多的内存.性能甚至可能受到影响,因为必须转换数据类型(在非常低的级别).

不是我想要的参考,但....

我的理解是底层VB引擎将整数转换为long,即使它被声明为整数.因此,可以注意到轻微的速度降低.我已经相信了一段时间,也许这就是为什么上面的陈述,我没有要求推理.

ozgrid论坛

这是我正在寻找的参考.

简而言之,在32位系统中,2字节整数被转换为4字节长.实际上没有其他方法可以使各个位正确排列以进行任何形式的处理.考虑以下

MsgBox Hex(-1) = Hex(65535) ' = True
Run Code Online (Sandbox Code Playgroud)

显然-1不等于65535但计算机正在返回正确答案,即"FFFF"="FFFF"

然而,如果我们强制-1到一个很长的第一个我们会得到正确的答案(65535大于32k自动很长)

MsgBox Hex(-1&) = Hex(65535) ' = False
Run Code Online (Sandbox Code Playgroud)

"FFFFFFFF"="FFFF"

通常,VBA在现代系统中声明"As Integer"没有任何意义,除非某些遗留API期望接收整数.

pcreview论坛

最后我发现了我真正想要的msdn文档.

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

因此,总而言之,现在几乎没有理由使用某种Integer类型.除非你需要使用期望16位int的旧API调用Interop.

值得指出的一点是,一些旧的API函数可能需要16位(2字节)整数的参数,如果你是32位并尝试传递一个整数(已经是4字节长)通过引用,由于字节长度的不同,它将无法工作.

感谢Vba4All指出了这一点.

  • 值得指出的一点是,一些旧的API函数可能需要16位(2字节)整数的参数,如果你是32位并尝试传递一个整数(已经是4字节长)通过引用,由于字节长度的不同,它将无法工作. (6认同)
  • 你*必须*使用`Integer`的另一个时间是声明`Type`,其中类型的布局和大小很重要,要么是因为你将类型传递给API,要么是序列化/反序列化文件,或者你用`LSet` /`Rset`复制字节. (3认同)
  • @Itbeenapleasure我不明白.如果你通过ref将一个Long传递给一个期望Integer by ref的函数,它将使用前两个字节,并且由于数字以little-endian存储,它将起作用(前提是只有两个较低的字节是有意义的,但是如果这个Long只是一个以32位存储的整数,那很可能. (2认同)

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,int32int64的系统数据类型,这使我能够更加透明地了解这些值.可以保存在这些数据类型中.


Ale*_* K. 7

VBA有很多历史包袱.

一个Integer16位宽,当16位架构/字大小普遍时,它是一个很好的默认数字类型.

A Long是32位宽,应尽可能使用(IMO).


PGS*_*ter 6

尽管这篇文章已有四年历史,但我对此很好奇,并进行了一些测试.最重要的是要注意编码器应该始终将变量声明为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)

  • 整齐!很高兴看到有人做了一些基准测试! (3认同)

Alt*_*ter 5

这是一个空间必要性的问题。

在某些情况下,有必要使用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)