微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

OMG!内存操作真危险

版权声明:可以任意转载,转载时请务必以链接形式标明如下文章原始出处和作者信息及本声明

作者:xixi

出处:http://blog.csdn.net/slowgrace/archive/2009/04/24/4105426.aspx

这篇文章里提到把API参数声明为ANY和声明为LONG的区别。昨天在这个帖子里试了试,还真是那么回事。感谢myjian耐心解释。

话说有个API函数RtlMoveMemory,我们可以有以下两种声明:

Private Declare Sub copyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long,ByVal Source As Long,ByVal Length As Long)
Private Declare Sub copyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any,Source As Any,ByVal Length As Long)

然后我们用下面的测试代码

Option Explicit

Private Type MyStruct
x
As Byte
y
As Byte
z
As Long
End Type

Private Sub Form_Load()
Dim t As MyStruct
With t
.x
= 12
.y
= 34
.z
= &H5678 '在内存中存放为 &H78 &H56 &H00 &H00
End With

Dim p As Long
Dim b As Byte
p
= VarPtr(t)

Call copyMemory(b,ByVal p + 2,1)
Debug.Print Hex(b)

Call copyMemory(b,ByVal p + 4,1)
Debug.Print Hex(b)
End Sub

这段代码大致的意思,是要验证VB6中结构的高字节对齐存储方式

如果用第一种声明就会导致内存溢出(我昨天尝试的后果是ACCESS死掉重启),用第二种就不会。主要是下面这个语句

Call copyMemory(b,ByVal p + 2,1)

这个语句的第二个参数是为了把P变量内的值(也就是变量t的内存地址)+2之后的那个"值"传进去,而不是P这个变量的地址,所以要加上BYVAL,因为声明里认是ByRef。而当声明里面不是声明为ByRef As Any而是ByVal As Long时,这个调用就可以是p+2了,可以省去ByVal说明。

而这个语句的第一个参数是要把变量b的地址传过去,如果使用ByVal as Long式声明的话,这样传进去的就是b的值(当时是0),向着0这个地址复制数据,当然会出错了。实际上,如果用ByVal as Long式声明的话,应该传vatPtr(b)才对。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐