送分80分:如何理解BYREF和BYVAL
有一个API函数定义如下:PRIVATE DECLARE SUB COPYMEMORY LIB "KERNEL32" (BYREF DESTINATION AS ANY ,BYREF SOURCE AS ANY ,BYVAL LENGTH AS LONG)
正常的用法
DIM A AS LONG ,B AS LONG,C AS LONG
A=1111
B=2222
C=4
COPYMEMORY(A,B,C)
而有的资料上有如下一个用法如何理解:
DIM K AS LONG
K=5
COPYMEMORY BYAL VARPRT(K),40000,4
前面函数定义中定义DESTINATION 时用的是BYREF 而具体用法中却用到了BYVAL如何理解。谢谢大家。 --------------------编程问答--------------------
BYREF是传地址、BYVAL是传值 --------------------编程问答-------------------- byerf 缺省,就是要变量的地址,
byval 就是要变量的值
比如,变量定义为 byval v as long
那么
dim v as long
v=6
就是将6传给函数。而如果是 byref v as long,那么就是将v的地址传给函数。
--------------------编程问答-------------------- VARPRT(K)取K的地址
然后BYAL VARPRT(K)传K地址
--------------------编程问答-------------------- 谢谢猴哥,我是想问一下,为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL。 --------------------编程问答-------------------- --------------------编程问答--------------------
谢谢猴哥,但是我的问题还是为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL.请注意我的问题。 --------------------编程问答-------------------- 先看这个函数
VarPtr(a):获取数值变量a的地址
把这个地址按值传递就是给函数传递了地址 --------------------编程问答--------------------
再次谢谢猴哥,但是我的问题还是
为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL
请一定要仔细体会一下我的问题。 --------------------编程问答--------------------
请看仔细,连人都认错了,仔细体会7楼的回答 --------------------编程问答--------------------
Declare ... (ByRef ... As Any, ... '表示参数是一个 void* 指针'
CopyMemory A, ... '取变量 A 的地址压栈,即堆栈中的指针值就是 A 的地址'
CopyMemory ByVal VarPtr(k), ... '表示将 Byval 后面的值压栈,由于 VarPtr 返回变量的地址,'
'所以堆栈中的指针值也是 K 的地址'
'假如换成没有 ByVal 的调用
CopyMemory VarPtr(k), ...
'该语句等价与
T = VarPtr(k) '取 K 的地址存入临时变量 T As Long 中'
CopyMemory T, ... '取变量 T 的地址压栈,即堆栈中的指针值变成了临时变量 T 的地址'
'它对 K 的指向变成了双重指针 void**,与预期不符'
--------------------编程问答-------------------- 楼主的代码怎么一堆大写,能否贴些完整的正规代码:) --------------------编程问答-------------------- 这么费劲,那我把我的问题 换个问法:
CopyMemory ByVal k,
和
CopyMemory k,
什么区别。 为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL
--------------------编程问答-------------------- 真不知道谁能给你说明白:
其实不管你是传地址,还传值,到了函数里都是要取变量里的值或给变量赋值对吧?
所谓传地址就是在函数里修改了byref a as...中a变量里的值,那么调用函数时所用的b变量里的值也会改,
仅些而已,并不是说定义了byref后就不能传值了,不知道说明白了吗?
--------------------编程问答-------------------- 定义的时候用BYREF,实际用的时候可以用BYREF也可以再指定为byval.效果一样
Private Sub Command1_Click()
Dim b As Integer
b = 5
MsgBox aa(b)
MsgBox aa(5) '这里你直接送个5也是可以的。
End Sub
Function aa(ByRef a As Integer) As Integer
a = a + 10
aa = a
End Function
--------------------编程问答-------------------- 打错了一个字:仅此而已
所谓传地址就是在函数里修改了byref a as...中a变量里的值,那么调用函数时所用的b变量里的值也会改,
仅此而已,并不是说定义了byref后就不能传值了,不知道说明白了吗? --------------------编程问答-------------------- 你首先要搞清楚,参数都是通过堆栈传递的,同样的堆栈内容,可以按照不同的声明有不同的解释。
VB 中简单点说
Declare 参数中,ByRef 取地址压栈,ByVal 取值压栈。
对于 Declare ...(ByRef 参数,调用时
CopyMemory K, ... 取 K 的地址压栈
CopyMemory ByVal K, ... 取 K 的值压栈,通常 K 值应该是一个有效的地址。 --------------------编程问答-------------------- 首先理解一个概念
变量其实就是内存中的一块区域,操作他的唯一方法就是操作这个变量的地址
将变量传给他其他函数当做参数调用时,可以传值,把这个变量的值传给其他函数
传址,把这个变量的地址传给其他函数,通常这样做,都是被调用的函数有要回传的数据时才这样
FF CC 33 11 <<< 变量值 (以long型距离,共4个字节的内容)
------------------------------------------------------
内存地址: &H400 - 00 01 02 03
传值 就是传递 FFCC3311(实际应该是1133ccff,不在本次讨论范围内)
传地址 就是传 &H40000,这个变量的起始地址。32位程序要传4个字节的长度,这是规定 --------------------编程问答-------------------- --------------------编程问答-------------------- 值的地址,地址的值,绕口令,绕的明白就明白了。
b= VARPTR(a)
值(a)的地址是一个值(b ),b 本身有 值、地址,b 的值就是a 的地址
BYREF a 等价于 BYVAL b --------------------编程问答-------------------- 参考我博客里《深入了解VB中的变量和指针(一)》一文。 --------------------编程问答-------------------- 看看能不能把你绕晕。
--------------------编程问答--------------------
Sub test()
Dim a As Long, b As Long, c As Long, d As Long, x As Long
a = 1234
b = VarPtr(a)
c = VarPtr(b)
d = VarPtr(c)
'从 d开始 逆运算 取得 a 的值 1234, 绕这么大个圈子其实就是 x = a
CopyMemory x, d, 4
Debug.Print x, d
CopyMemory x, ByVal x, 4
Debug.Print x, c
CopyMemory x, ByVal x, 4
Debug.Print x, b
CopyMemory x, ByVal x, 4
Debug.Print x, a
End Sub
CopyMemory ByVal k, 把一些内存复制到K 指向的内存地址,之前必须有 K = varptr(xx),此处的k 是一个路标(或者说快捷方式),指向某个目的地。
CopyMemory k, 把一些内存复制到K ,此时的k 本身就是目的地。
给c盘建个快捷方式,放到桌面,你把某个文件拖到这个快捷方式上面,和你直接把某文件拖到C盘,结果是一样的
这样说,好理解了吧。
--------------------编程问答-------------------- VB《葵花宝典》--指针技术这篇文章真是经典,我半年内已经看了三四遍了,今天又看了一遍,又有新的领悟,可能和本问题的解决有帮助。
心得:
比如定义一个变量: DIM K AS LONG 它有两个值可供函数使用,变量值和变量的内存地址值。
当函数调用时
COPYMEMORY BYVAL K 是把K的变量值传递给函数的形参Destination。
COPYMEMORY BYREF K 是把K的内存地址值传递给函数的形参Destination。
也就是说在函数在具体调用时将变量K的两个数值(变量值、变量地址值)传给形参Destination之前,BYVAL和BYREF分别决定了是将K的变量值传给形参Destination还是将K的变量地址值传给形参Destination。
具体将变量K的哪个值与函数的定义【SUB COPYMEMORY (BYREF DESTINATION AS ANY ,BYREF SOURCE AS ANY ,BYVAL LENGTH AS LONG)】的中BYREF DESTINATION AS ANY 中的BYREF毫无关系。
具体传哪个值给形参DESTINATION只取决于此函数具体调用时,K前用的是BYVAL还是BYREF。
我的天呀,不知道大家能看懂吧。 请大家帮我看看对不对。 --------------------编程问答-------------------- 如果你不太了解传址,传值的概念,不建议你用copymemory做例子
在某些极端的copymemory使用情况下, 用几次你就得晕了
还是做些普通的传值,传址的应用慢慢熟悉下吧 --------------------编程问答--------------------
老盖规定可以这么用 行了吧^_ --------------------编程问答-------------------- 你可以这样假想:
1)
CopyMemory k,
直接调用你开头声明的函数
Declare ... CopyMemory ... (ByRef Var As Any
2)
CopyMemory ByVal k,
ByVal 改变了参数的定义方式,等于又声明了一个函数
Declare ... CopyMemory2 ... (ByVal lpVar As Long
实际调用就成为了
CopyMemory2 k,
--------------------编程问答-------------------- API声明中:
ByRef XXX As Long = API将接收这个变量的地址,类型描述(Long)换成了Any时,代表接收任何变量的地址,因为不再做变量类型检查了.
ByVal XXX As Long = API将接收这个变量的值
调用时:
一,API声明为ByRef XXX As Any的情况:
dim II as long
ii=10000
call CopyMemory(ByVal II........ '将II的值(10000)传入
call CopyMemory(II........ '将II这个变量传入,API将自动取得变量II的地址
二,API声明为ByVal XXX As Long的情况:
dim II as long
ii=10000
call CopyMemory(ByVal II........ '将II的值(10000)传入
call CopyMemory(II........ '将II这个变量传入,API将自动取得变量II的值
这里其实是两方面的情况,一是接收方,二是调用方.
所以情况稍微复杂了点.
支持上面PctGL的说法,不建议你一上来就用这个CopyMemory做例子,组合太多,一个不小心就晕了. --------------------编程问答-------------------- 不要执着于表面上的申明, 透过现象看本质, CopyMemory就是从一个地址拷贝一定长度的数据到另一个地址而已. 因此只要你能确定前两个参数代表的是地址就可以了. --------------------编程问答-------------------- 学点汇编就不会那么纠结了。 --------------------编程问答--------------------
简单地说,Byref 传递的是数据在内存中的地址,Byval 传的是数据本身。
例如,一个数字 999 存放在地址 8000。Byval 是将数字 999 作为参数直接传过去;而 Byref 是将地址 8000 传过去,让接收方按地址去取数。
你所说的问题在于,函数缺省的是传址,而 VARPRT(K) 已经是一个地址。如果 Byref 就会传一个地址的地址过去,所以要 Byval 修正一下。
补充:VB , 网络编程