You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VBA私有Long数组元素莫名变为-1的问题求助

VBA私有数组元素莫名显示-1的问题排查

我在支持Excel的项目中实现了包含UDF的模块与类,其中一个类定义了私有Long数组m_FromLastGuess,类初始化时将数组所有元素设为0,仅通过IncrementFromLastGuess方法对数组元素执行递增操作,另有Dump方法将数组内容写入statistics.txt文件。但输出结果显示m_FromLastGuess(0)的值为-1,逻辑上该元素仅能被递增,不可能出现负值。

完整类代码

Option Explicit

Private m_FromLastMethodCalls As Long
Private m_FromLastBinarySearchMiss As Long
Private m_FromLastBinarySearchHit As Long
Private m_FromLastBinarySearchAdd As Long
Private m_FromLastBinarySearchLastHitIndex As Long
Private m_FromLastGuess(2) As Long
Private m_FromLastCreateTargetsCollection As Long
Private m_FromLastRetrieveCachedTargetsCollection As Long
Private m_FromLastError As Long

Public Function IncrementFromLastMethodCalls()
    m_FromLastMethodCalls = m_FromLastMethodCalls + 1
End Function
Public Function IncrementFromLastBinarySearchMiss()
    m_FromLastBinarySearchMiss = m_FromLastBinarySearchMiss + 1
End Function
Public Function IncrementFromLastBinarySearchHit()
    m_FromLastBinarySearchHit = m_FromLastBinarySearchHit + 1
End Function
Public Function IncrementFromLastBinarySearchAdd()
    m_FromLastBinarySearchAdd = m_FromLastBinarySearchAdd + 1
End Function
Public Function IncrementFromLastCreateTargetsCollection()
    m_FromLastCreateTargetsCollection = m_FromLastCreateTargetsCollection + 1
End Function
Public Function IncrementFromLastRetrieveCachedTargetCollection()
    m_FromLastRetrieveCachedTargetsCollection = m_FromLastRetrieveCachedTargetsCollection + 1
End Function
Public Function IncrementFromLastError()
    m_FromLastError = m_FromLastError + 1
End Function
Public Property Let lastHitIndex(lastHitIndex As Long)
    m_FromLastBinarySearchLastHitIndex = lastHitIndex
End Property
Public Property Get lastHitIndex() As Long
    lastHitIndex = m_FromLastBinarySearchLastHitIndex
End Property
Public Function IncrementFromLastGuess(guessNumber As Integer)
    m_FromLastGuess(guessNumber) = m_FromLastGuess(guessNumber) + 1
End Function


Public Function Dump()
    Open "statistics.txt" For Append As #1 ' Open file for output.
    Print #1, Format(Now(), "YYYY-MM-DD HH:MM:SS")
    Print #1, "FromLastMethodCalls:                     " & Format(Format(m_FromLastMethodCalls, "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastBinarySearchMiss:                " & Format(Format(m_FromLastBinarySearchMiss, "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastBinarySearchHit:                 " & Format(Format(m_FromLastBinarySearchHit, "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastBinarySearchAdd:                 " & Format(Format(m_FromLastBinarySearchAdd, "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastGuess(0):                        " & Format(Format(m_FromLastGuess(0), "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastGuess(1):                        " & Format(Format(m_FromLastGuess(1), "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastGuess(2):                        " & Format(Format(m_FromLastGuess(2), "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastError:                           " & Format(Format(m_FromLastError, "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastCreateTargetsCollection:         " & Format(Format(m_FromLastCreateTargetsCollection, "##,###,##0"), "@@@@@@@@@@")
    Print #1, "FromLastRetrieveCachedTargetsCollection: " & Format(Format(m_FromLastRetrieveCachedTargetsCollection, "##,###,##0"), "@@@@@@@@@@")
    Dim total As Long
    total = m_FromLastError + m_FromLastCreateTargetsCollection + m_FromLastRetrieveCachedTargetsCollection
    Print #1, "Total:                                   " & Format(Format(total, "##,###,##0"), "@@@@@@@@@@")
    Close #1
    
    m_FromLastMethodCalls = 0
    m_FromLastBinarySearchMiss = 0
    m_FromLastBinarySearchHit = 0
    m_FromLastBinarySearchAdd = 0
    m_FromLastGuess(0) = m_FromLastGuess(1) = m_FromLastGuess(2) = 0
    m_FromLastCreateTargetsCollection = 0
    m_FromLastRetrieveCachedTargetsCollection = 0
    m_FromLastError = 0
End Function

Private Sub Class_Initialize()
    m_FromLastBinarySearchLastHitIndex = -1
    m_FromLastGuess(0) = m_FromLastGuess(1) = m_FromLastGuess(2) = 0
End Sub

相关说明

  • m_FromLastGuess为私有Long类型数组,预期包含3个元素(下标0、1、2)
  • IncrementFromLastGuess是唯一修改该数组的方法,仅执行递增操作
  • Dump方法中输出数组元素的代码片段:
Print #1, "FromLastGuess(0):                        " & Format(Format(m_FromLastGuess(0), "##,###,##0"), "@@@@@@@@@@")
Print #1, "FromLastGuess(1):                        " & Format(Format(m_FromLastGuess(1), "##,###,##0"), "@@@@@@@@@@")
Print #1, "FromLastGuess(2):                        " & Format(Format(m_FromLastGuess(2), "##,###,##0"), "@@@@@@@@@@")

输出文件内容

2023-05-26 10:41:54
FromLastMethodCalls:                              0
FromLastBinarySearchMiss:                         0
FromLastBinarySearchHit:                          0
FromLastBinarySearchAdd:                          0
FromLastGuess(0):                                -1
FromLastGuess(1):                            10,535
FromLastGuess(2):                               856
FromLastError:                                    0
FromLastCreateTargetsCollection:                  0
FromLastRetrieveCachedTargetsCollection:          0
Total:                                            0

问题根源与解决方法

问题根源:数组下标越界访问

问题出在数组声明与访问逻辑不匹配:

  1. 数组声明未明确指定下界:类中数组声明为Private m_FromLastGuess(2) As Long,若类模块中设置了Option Base 1(模块级设置,默认数组下界为1),则该数组实际仅包含2个元素(下标1、2),而非预期的3个。
  2. 越界访问读取相邻变量:代码中访问m_FromLastGuess(0)时,因数组无0下标,会越界读取类中前一个成员变量m_FromLastBinarySearchLastHitIndex的值,而该变量在Class_Initialize中被初始化为-1,因此输出结果显示为-1。

验证依据

  • 输出中m_FromLastGuess(1)和m_FromLastGuess(2)的值正常递增,符合数组元素的操作逻辑;
  • m_FromLastGuess(0)的值与m_FromLastBinarySearchLastHitIndex的初始化值完全一致,进一步确认是越界访问导致。

解决方法

  1. 明确指定数组下界:修改数组声明为Private m_FromLastGuess(0 To 2) As Long,强制数组下标范围为0-2,不受Option Base设置影响。
  2. 添加参数合法性校验:在IncrementFromLastGuess方法中加入参数校验,避免传入非法下标导致越界:
Public Function IncrementFromLastGuess(guessNumber As Integer)
    ' 校验下标范围
    If guessNumber < 0 Or guessNumber > 2 Then
        Err.Raise vbObjectError + 1001, , "Invalid guessNumber: must be 0, 1, or 2"
    End If
    m_FromLastGuess(guessNumber) = m_FromLastGuess(guessNumber) + 1
End Function

内容的提问来源于stack exchange,提问作者mbmast

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 01:38:11