首页 /编程语言和算法/VB6/ASP
 VB6 计算数据类型占用内存大小(占几个字节)隐藏函数 VarPtr StrPtr 看变量地址
2023年11月25日 18:00

需求背景

C、C++和.net语言都提供了计算变量内存大小的函数即SizeOf,该函数能正确返回数据类型占用的内存字节数,但是VBA、VB6.0没有直接提供。特别在调用Windows API的时候,该功能显示得特别重要。

实现思路

VB6.0虽然没有提供指针运算符,但提供了几个获取变量指针(内存地址)的值的函数。

新建From1(窗体),新建t(TextBox),Command1、Command2(按钮CommandButton),代码:

具体代码只能由VIP查看,请升级

运行结果:(&H是我后期添加的结论)

VarPtr(i(1))  = 142505232
VarPtr(i(2))  = 142505234
VarPtr(i(3))  = 142505236
VarPtr(i(4))  = 142505238
VarPtr(i(5))  = 142505240
----------
StrPtr(i(1))  = 142505180
StrPtr(i(2))  = 142505180
StrPtr(i(3))  = 142505180
StrPtr(i(4))  = 142505180
StrPtr(i(5))  = 142505180
----------
VarPtr(l(1))   = 377404000
VarPtr(l(2))   = 377404004
VarPtr(l(3))   = 377404008
VarPtr(l(4))   = 377404012
VarPtr(l(5))   = 377404016
----------
StrPtr(l(1))  = 142505180
StrPtr(l(2))  = 142505180
StrPtr(l(3))  = 142505180
StrPtr(l(4))  = 142505180
StrPtr(l(5))  = 142505180
----------
VarPtr(s(1))  = 377404192
VarPtr(s(2))  = 377404196
VarPtr(s(3))  = 377404200
VarPtr(s(4))  = 377404204
VarPtr(s(5))  = 377404208
----------
StrPtr(s(1))  = 379393388
StrPtr(s(2))  = 379393820
StrPtr(s(3))  = 379393892
StrPtr(s(4))  = 142505516
StrPtr(s(5))  = 142505068
----------
VarPtr(s1)  = 1700212
VarPtr(s2)  = 1700196
VarPtr(s3)  = 1700180
VarPtr(s4)  = 1700164
VarPtr(s5)  = 1700160
----------
StrPtr(s1)  = 146467388 &H8BAEA3C
StrPtr(s2)  = 379394324 &H169D1914
StrPtr(s3)  = 379366460 &H169CAC3C
StrPtr(s4)  = 142506020 &H87E7824
StrPtr(s5)  = 142504676 &H87E72E4
----------
__________________________________________________________________________________________
Start Address = &H8BAEA3C	 Number of Bytes = 32

Address:  OS:   Memory:                                        ASCII:
08BAEA3C  0000  77 00 77 00 77 00 2E 00 6D 00 61 00 6E 00 6F   w.w.w...m.a.n.o.
08BAEA4C  0010  6E 00 67 00 6B 00 75 00 2E 00 63 00 6F 00 6D   n.g.k.u...c.o.m.
__________________________________________________________________________________________
__________________________________________________________________________________________
Start Address = &H169D1914	 Number of Bytes = 32

Address:  OS:   Memory:                                        ASCII:
169D1914  0000  47 00 6F 00 6F 00 64 00 21 00 1F 77 84 76 7D   G.o.o.d.!..w.v}Y
169D1924  0010  E6 54 2E 00 00 00 00 00 00 00 00 00 57 81 02   .T..........W...
__________________________________________________________________________________________
__________________________________________________________________________________________
Start Address = &H169CAC3C	 Number of Bytes = 32

Address:  OS:   Memory:                                        ASCII:
169CAC3C  0000  59 00 65 00 73 00 2E 00 00 00 44 00 4C 00 4C   Y.e.s.....D.L.L.
169CAC4C  0010  00 00 00 00 06 00 00 00 08 00 00 00 3F 34 03   ............?4..
__________________________________________________________________________________________
__________________________________________________________________________________________
Start Address = &H87E7824	 Number of Bytes = 32

Address:  OS:   Memory:                                        ASCII:
087E7824  0000  4F 00 6B 00 61 00 79 00 2E 00 00 00 57 E0 E1   O.k.a.y.....W...
087E7834  0010  57 E0 E1 E4 5E E9 8F EC E4 43 72 47 F9 AB 23   W...^....CrG..#G
__________________________________________________________________________________________
__________________________________________________________________________________________
Start Address = &H87E72E4	 Number of Bytes = 32

Address:  OS:   Memory:                                        ASCII:
087E72E4  0000  48 00 69 00 2E 00 00 00 00 00 00 00 97 EA E1   H.i.............
087E72F4  0010  97 EA E1 E4 9E E3 8F EC 24 49 72 47 ED E7 23   ........$IrG..#G
__________________________________________________________________________________________

其它数据类型都可以通过这样的方式来计算出内存的大小,这样调用Windows API 就非常方便了。

 
全部回复(5)
  • 引用1楼

    关于 77 00 ,参考 《VB6 串口通信,发送正常,接收的数据总是不对,数据中多了几个 00

    上方如果

    s1 = "www.manongku.com"

    变成了

    s1 = "我www.manongku.com"

    那么汉字在内存中就是就是:

    11 62 77 00 77 00 77 00 2E 00...

    关于 62 11 = 我,参考《VB6 将Unicode转中文

    看来Intel系列采用小端序,把低位的11放在低端,把高位的62放到高端。

  • 引用2楼

    深入一下:

    如果我们在代码

         '后续结果随机
        t.Text = t.Text & "StrPtr(s1)  = " & StrPtr(s1) & vbCrLf
        t.Text = t.Text & "StrPtr(s2)  = " & StrPtr(s2) & vbCrLf
        t.Text = t.Text & "StrPtr(s3)  = " & StrPtr(s3) & vbCrLf
        t.Text = t.Text & "StrPtr(s4)  = " & StrPtr(s4) & vbCrLf
        t.Text = t.Text & "StrPtr(s5)  = " & StrPtr(s5) & vbCrLf
        t.Text = t.Text & strLine

    后修改s1、s2从而变成:

         '后续结果随机
        t.Text = t.Text & "StrPtr(s1)  = " & StrPtr(s1) & vbCrLf
        t.Text = t.Text & "StrPtr(s2)  = " & StrPtr(s2) & vbCrLf
        t.Text = t.Text & "StrPtr(s3)  = " & StrPtr(s3) & vbCrLf
        t.Text = t.Text & "StrPtr(s4)  = " & StrPtr(s4) & vbCrLf
        t.Text = t.Text & "StrPtr(s5)  = " & StrPtr(s5) & vbCrLf
        t.Text = t.Text & strLine
        
        s1 = "你好www.manongku.com"
        s2 = "Hiwww.qq.com"
         '后续结果随机2
        t.Text = t.Text & "StrPtr(s1)  = " & StrPtr(s1) & vbCrLf
        t.Text = t.Text & "StrPtr(s2)  = " & StrPtr(s2) & vbCrLf
        t.Text = t.Text & "StrPtr(s3)  = " & StrPtr(s3) & vbCrLf
        t.Text = t.Text & "StrPtr(s4)  = " & StrPtr(s4) & vbCrLf
        t.Text = t.Text & "StrPtr(s5)  = " & StrPtr(s5) & vbCrLf
        t.Text = t.Text & strLine

    可以看到运行结果修改了的s1、s2变了地址,而没修改的s3、s4、s5地址不变。看来是CPU重新申请了地址。

    StrPtr(s1)  = 192503724
    StrPtr(s2)  = 63122836
    StrPtr(s3)  = 63122276
    StrPtr(s4)  = 191219644
    StrPtr(s5)  = 191219668
    ----------
    StrPtr(s1)  = 192506316
    StrPtr(s2)  = 63122476
    StrPtr(s3)  = 63122276
    StrPtr(s4)  = 191219644
    StrPtr(s5)  = 191219668
    ----------

    显示试试数组:

        s(1) = "www.manongku.com"
        s(2) = "Good!真的好哦."
        s(3) = "Yes."
        s(4) = "Okay."
        s(5) = "Hi."
    
        t.Text = ""
        
        t.Text = t.Text & StrPtr(s(1)) & vbCrLf
        t.Text = t.Text & StrPtr(s(2)) & vbCrLf
        t.Text = t.Text & StrPtr(s(3)) & vbCrLf
        t.Text = t.Text & StrPtr(s(4)) & vbCrLf
        t.Text = t.Text & StrPtr(s(5)) & vbCrLf & vbCrLf
        
        s(1) = "你好www.manongku.com"
        s(2) = "HiGood!真的好哦."
        
        t.Text = t.Text & StrPtr(s(1)) & vbCrLf
        t.Text = t.Text & StrPtr(s(2)) & vbCrLf
        t.Text = t.Text & StrPtr(s(3)) & vbCrLf
        t.Text = t.Text & StrPtr(s(4)) & vbCrLf
        t.Text = t.Text & StrPtr(s(5)) & vbCrLf

    运行结果也一样,修改了的字符串地址会变动,没修改的字符串不会变动。代码如下:

        s(1) = "www.manongku.com"
        s(2) = "Good!真的好哦."
        s(3) = "Yes."
        s(4) = "Okay."
        s(5) = "Hi."
    
        t.Text = ""
        
        t.Text = t.Text & StrPtr(s(1)) & vbCrLf
        t.Text = t.Text & StrPtr(s(2)) & vbCrLf
        t.Text = t.Text & StrPtr(s(3)) & vbCrLf
        t.Text = t.Text & StrPtr(s(4)) & vbCrLf
        t.Text = t.Text & StrPtr(s(5)) & vbCrLf & vbCrLf
        
        s(1) = "你好www.manongku.com"
        s(2) = "HiGood!真的好哦."
        
        t.Text = t.Text & StrPtr(s(1)) & vbCrLf
        t.Text = t.Text & StrPtr(s(2)) & vbCrLf
        t.Text = t.Text & StrPtr(s(3)) & vbCrLf
        t.Text = t.Text & StrPtr(s(4)) & vbCrLf
        t.Text = t.Text & StrPtr(s(5)) & vbCrLf

    运行结果:

    192499908
    63992044
    63992724
    63991604
    63992884
    
    192504084
    192902316
    63992724
    63991604
    63992884

    现在看下定长字符串:

    如果把

    Dim s(1 To 5) As String

    改成

    Dim s(1 To 5) As String * 100

    那么运行结果就是不变:

    192607964
    192607964
    192607964
    192607964
    192607964
    
    192607964
    192607964
    192607964
    192607964
    192607964

    对于数组肯定也是不变的,因为本身就是定长,代码如下:

        t.Text = ""
        
        t.Text = t.Text & VarPtr(i(1)) & vbCrLf
        t.Text = t.Text & VarPtr(i(2)) & vbCrLf
        t.Text = t.Text & VarPtr(i(3)) & vbCrLf
        t.Text = t.Text & VarPtr(i(4)) & vbCrLf
        t.Text = t.Text & VarPtr(i(5)) & vbCrLf & vbCrLf
        
        i(1) = 6
        i(2) = 7
        i(3) = 3
        i(4) = 4
        i(5) = 5
        
        t.Text = t.Text & VarPtr(i(1)) & vbCrLf
        t.Text = t.Text & VarPtr(i(2)) & vbCrLf
        t.Text = t.Text & VarPtr(i(3)) & vbCrLf
        t.Text = t.Text & VarPtr(i(4)) & vbCrLf
        t.Text = t.Text & VarPtr(i(5)) & vbCrLf

    运行结果:

    64083368
    64083370
    64083372
    64083374
    64083376
    
    64083368
    64083370
    64083372
    64083374
    64083376

    关于字符串数组占用内存的测试报告,请看《VB6 如何节约内存?Dim定义到过程当局部变量与全局的区别》。

  • 引用3楼

    对于变量,看下它在不同子程序中是否被复制?

    Private Sub Command1_Click()
        Dim arr(0) As Byte
        arr(0) = 65
        Debug.Print VarPtr(0)
        Call s_1(arr)
    End Sub
    
    Private Sub s_1(arr() As Byte)
        Debug.Print VarPtr(0)
        Call s_2(arr)
    End Sub
    
    Private Sub s_2(arr() As Byte)
        Debug.Print VarPtr(0)
    End Sub

    运行结果:

     1700298 
     1700142 
     1699986

    证明了,再次调用,测试局部变量或全局变量地址也会变,这样效率低。能节省s_1就不用s_1最快。

  • 引用4楼
    Private Sub Command1_Click()
        Dim bArr() As Byte
    
        ReDim bArr(10)
        Debug.Print VarPtr(bArr(0))
        
        ReDim Preserve bArr(10)
        Debug.Print VarPtr(bArr(0))
        
         ReDim bArr(20)
        Debug.Print VarPtr(bArr(0))
        
        ReDim Preserve bArr(20)
        Debug.Print VarPtr(bArr(0))
    End Sub

    运行结果:

     197909000 
     197909000 
     63627392 
     63627392


  • 引用5楼

    看代码:

    Private Sub Command1_Click()
        Dim s1 As String
        
        s1 = "www.manongku.com"
        Debug.Print StrPtr(s1)
        
        s1 = Left$(s1, 1)
        Debug.Print StrPtr(s1)
        
        s1 = "码农库"
        Debug.Print StrPtr(s1)
    End Sub

    运行结果:

     198742284 
     197567756 
     197570516

    如果字符串缩小,地址也会变,不存在直接给字符串截取后加0而节约的情况。增加也会变。

  • 首页 | 电脑版 |