那些网站可以做0首付分期手机号,灵宝网站建设,0元开网店,中山门户网站制作在哪里买目录 1. 主要区别
2. 例释(以Windows X64平台为例) 1. 主要区别 在函数传参中#xff0c;传引用在本质上就是传地址#xff0c;而传值调用是利用函数的栈空间进行传递#xff0c;先将实体复制一份到栈内存#xff0c;再通过内存栈传递参数。同时#xff0c;通过传引…目录 1. 主要区别
2. 例释(以Windows X64平台为例) 1. 主要区别 在函数传参中传引用在本质上就是传地址而传值调用是利用函数的栈空间进行传递先将实体复制一份到栈内存再通过内存栈传递参数。同时通过传引用和传地址的任何对象如果改动了任何属性是直接改动原对象而传值只会改变副本不会改变原对象。
2. 例释(以Windows X64平台为例) 为了简单起见定义一个结构体
struct DataEntity
{ __int64 m 0x1111111111111111; //为了便于观察内存每一个字节都赋值 __int64 n 0x2222222222222222; __int64 Add() { return m n; }
};
定义三个函数分别按传地址传引用传值方式传参
void PrintPassByReference(DataEntity data)
{ __int64 total data.m data.n;
} void PrintPassByPtr(DataEntity* data)
{ __int64 total data-m data-n;
} void PrintPassByValue(DataEntity data)
{ __int64 total data.m data.n;
}
调用代码 DataEntity data; PrintPassByReference(data); PrintPassByPtr(data); PrintPassByValue(data);
汇编代码分析 DataEntity data;
00007FF658FD50A3 lea rcx,[data]
00007FF658FD50A8 call DataEntity::DataEntity (07FF658E56F55h) PrintPassByReference(data);
00007FF658FD50AD lea rcx,[data] ; 将 data 的地址存入寄存器rcx
00007FF658FD50B2 call PrintPassByReference (07FF658E56F5Ah)
进入 PrintPassByReference
void PrintPassByReference(DataEntity data)
{
00007FF658FD4FE0 mov qword ptr [rsp8],rcx 取出data的地址
00007FF658FD4FE5 sub rsp,18h __int64 total data.m data.n;
00007FF658FD4FE9 mov rax,qword ptr [data] ;将data首地址送入rax
00007FF658FD4FEE mov rax,qword ptr [rax]
00007FF658FD4FF1 mov rcx,qword ptr [data]
00007FF658FD4FF6 add rax,qword ptr [rcx8]
00007FF658FD4FFA mov qword ptr [rsp],rax
}
00007FF658FD4FFE add rsp,18h
00007FF658FD5002 ret PrintPassByPtr(data);
00007FF658FD50B7 lea rcx,[data] 将 data 的地址存入寄存器 rcx
00007FF658FD50BC call PrintPassByPtr (07FF658E56F69h)
;可以看出在调用方式上与 PrintPassByReference 相同。
进入 PrintPassByPtr(data);
void PrintPassByPtr(DataEntity* data)
{
00007FF658FD5010 mov qword ptr [rsp8],rcx ;取出data的地址
00007FF658FD5015 sub rsp,18h __int64 total data-m data-n;
00007FF658FD5019 mov rax,qword ptr [data]
00007FF658FD501E mov rax,qword ptr [rax]
00007FF658FD5021 mov rcx,qword ptr [data]
00007FF658FD5026 add rax,qword ptr [rcx8]
00007FF658FD502A mov qword ptr [rsp],rax
}
00007FF658FD502E add rsp,18h
00007FF658FD5032 ret
从以上可以看出PrintPassByReference 和 PrintPassByPtr 生成的汇编代码基本一致二者都是直接传递数据的地址。
现在看看在进入PrintPassByValue之前的准备 PrintPassByValue(data);
00007FF658FD50C1 lea rax,[rsp40h] ;分配 40h 的栈空间
00007FF658FD50C6 lea rcx,[data] ;取得 data 的地址
00007FF658FD50CB mov rdi,rax ; 分配的空间地址送入寄存器rdi
00007FF658FD50CE mov rsi,rcx ; data 送入寄存器 rsi
00007FF658FD50D1 mov ecx,10h 计数器值赋为 16 (data大小为16字节)
00007FF658FD50D6 rep movs byte ptr [rdi],byte ptr [rsi] 按字节复制data到新的空间
00007FF658FD50D8 lea rcx,[rsp40h] 将栈空间地址送入rcx
00007FF658FD50DD call PrintPassByValue (07FF658E56F5Fh)
说明以上红色部分为新分配栈空间并复制对象副本这个过程对于 C 程序员是隐藏的。
进入 PrintPassByValue
void PrintPassByValue(DataEntity data)
{
00007FF66BA05040 mov qword ptr [rsp8],rcx 取出栈中存储的data副本
00007FF66BA05045 sub rsp,18h __int64 total data.m data.n;
00007FF66BA05049 mov rax,qword ptr [data] 这个data是栈中存储的副本
00007FF66BA0504E mov rax,qword ptr [rax]
00007FF66BA05051 mov rcx,qword ptr [data]
00007FF66BA05056 add rax,qword ptr [rcx8]
00007FF66BA0505A mov qword ptr [rsp],rax
}
00007FF66BA0505E add rsp,18h
00007FF66BA05062 ret
传值是对副本对应的内存进行操作当然不会改变原对象。