当前位置:编程学习 > VB >>

送分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如何理解。谢谢大家。 --------------------编程问答--------------------
引用楼主 shuanglongmm 的回复:
如何理解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。 --------------------编程问答-------------------- --------------------编程问答--------------------
引用 5 楼 chinaboyzyq 的回复:
看#3


谢谢猴哥,但是我的问题还是为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL.请注意我的问题。 --------------------编程问答-------------------- 先看这个函数
VarPtr(a):获取数值变量a的地址


把这个地址按值传递就是给函数传递了地址 --------------------编程问答--------------------
引用 7 楼 jhone99 的回复:
先看这个函数
VarPtr(a):获取数值变量a的地址


把这个地址按值传递就是给函数传递了地址


再次谢谢猴哥,但是我的问题还是

      为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL

请一定要仔细体会一下我的问题。 --------------------编程问答--------------------
引用 8 楼 shuanglongmm 的回复:
引用 7 楼 jhone99 的回复:
先看这个函数
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后就不能传值了,不知道说明白了吗?


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,实际用的时候可以用BYREF也可以再指定为byval.效果一样
--------------------编程问答-------------------- 打错了一个字:仅此而已

所谓传地址就是在函数里修改了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
--------------------编程问答--------------------
引用 12 楼 shuanglongmm 的回复:
这么费劲,那我把我的问题 换个问法:

  CopyMemory ByVal k,

  和 

  CopyMemory k,

  什么区别。 为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL


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使用情况下, 用几次你就得晕了

还是做些普通的传值,传址的应用慢慢熟悉下吧 --------------------编程问答--------------------
引用 12 楼 shuanglongmm 的回复:
这么费劲,那我把我的问题 换个问法:

  CopyMemory ByVal k,

  和 

  CopyMemory k,

  什么区别。 为什么函数定义中用的是BYREF,而具体函数使用中却可以用BYVAL

老盖规定可以这么用 行了吧^_ --------------------编程问答-------------------- 你可以这样假想:

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 ,  网络编程
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,