OMG!内存操作真危险

前端之家收集整理的这篇文章主要介绍了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)才对。

原文链接:https://www.f2er.com/vb/263099.html

猜你在找的VB相关文章