编译器如何理解C++的指针和引用?

news2025/6/28 8:25:55

        初学引用时,往往很难真正理解引用,它与指针究竟有什么区别和联系。下面我们不妨看看编译器如何理解引用和指针的。

一.函数通过指针传参

1.1 示例代码

#include <iostream>

using namespace std;

void swap(int *x,int *y)//指针传参 
{
	int tmp;
	tmp = *x;
	*x = *y;
	*y = tmp;
}

int main(int argc, char** argv) 
{
	int a = 20;
	int b = 30;
	
	swap(&a,&b);//指针传参 
	
	return 0;
}

1.2 汇编代码

1.2.1 main函数汇编代码

<+0>:	push   %rbp
<+1>:	mov    %rsp,%rbp
<+4>:	sub    $0x30,%rsp
<+8>:	mov    %ecx,0x10(%rbp)
<+11>:	mov    %rdx,0x18(%rbp)
<+15>:	callq  0x40e780 <__main>
<+20>:	movl   $0x14,-0x4(%rbp)//栈中偏移4的空间初始化为20,即int a = 20
<+27>:	movl   $0x1e,-0x8(%rbp)//栈中偏移8的空间初始化为30,即int b = 30
<+34>:	lea    -0x8(%rbp),%rdx//取b的地址传给rdx
<+38>:	lea    -0x4(%rbp),%rax//取a的地址传给rax
<+42>:	mov    %rax,%rcx//rax的值传给rcx,即a的地址保存到rcx中
<+45>:	callq  0x401530 <swap(int*, int*)>//引用传参的函数
<+50>:	mov    $0x0,%eax
<+55>:	add    $0x30,%rsp
<+59>:	pop    %rbp
<+60>:	retq   

 由上图可知:

(1)main函数在栈中开辟了两个4字节空间,分别分配给a和b,并且分别初始化为20和30

<+20>:	movl   $0x14,-0x4(%rbp)//栈中偏移4的空间初始化为20,即int a = 20
<+27>:	movl   $0x1e,-0x8(%rbp)//栈中偏移8的空间初始化为30,即int b = 30

(2)准备传给swap函数的参数

<+34>:	lea    -0x8(%rbp),%rdx//取b的地址传给rdx
<+38>:	lea    -0x4(%rbp),%rax//取a的地址传给rax
<+42>:	mov    %rax,%rcx //rax的值传给rcx,即a的地址保存到rcx中
<+45>:	callq  0x401530 <swap(int&, int&)>//引用传参的函数

        swap函数的参数分别保存在rcx和rdx中,且是参数地址。

1.2.2 swap函数汇编代码

<+0>:	push   %rbp
<+1>:	mov    %rsp,%rbp
<+4>:	sub    $0x10,%rsp
<+8>:	mov    %rcx,0x10(%rbp)//a的地址保存到栈中(对应形参x)
<+12>:	mov    %rdx,0x18(%rbp)//b的地址保存到栈中(对应形参y)
<+16>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+20>:	mov    (%rax),%eax//a的值赋给eax(4字节)
<+22>:	mov    %eax,-0x4(%rbp)//eax的值赋给栈偏移为4的变量tmp中,即tmp = a
<+25>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+29>:	mov    (%rax),%edx//b的值赋给edx(4字节)
<+31>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+35>:	mov    %edx,(%rax)//eax的值赋给a,即a = b
<+37>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+41>:	mov    -0x4(%rbp),%edx//edx = tmp
<+44>:	mov    %edx,(%rax) //b = edx,即b = tmp
<+46>:	add    $0x10,%rsp
<+50>:	pop    %rbp
<+51>:	retq  

        由上图可知:

(1)swap函数接收了a和b变量的地址

<+8>:	mov    %rcx,0x10(%rbp)//a的地址保存到栈中(对应形参x)
<+12>:	mov    %rdx,0x18(%rbp)//b的地址保存到栈中(对应形参y)

(2)直接交换a、b空间的值

<+16>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+20>:	mov    (%rax),%eax//a的值赋给eax(4字节)
<+22>:	mov    %eax,-0x4(%rbp)//eax的值赋给栈偏移为4的变量tmp中,即tmp = a
<+25>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+29>:	mov    (%rax),%edx//b的值赋给edx(4字节)
<+31>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+35>:	mov    %edx,(%rax)//eax的值赋给a,即a = b
<+37>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+41>:	mov    -0x4(%rbp),%edx//edx = tmp
<+44>:	mov    %edx,(%rax) //b = edx,即b = tmp

二.函数通过引用传参

2.1 示例代码

#include <iostream>

using namespace std;

void swap(int &x,int &y)//引用传参 
{
	int tmp;
	tmp = x;
	x = y;
	y = tmp;
}

int main(int argc, char** argv) 
{
	int a = 20;
	int b = 30;
	
	swap(a,b);//引用传参 
	
	return 0;
}

2.2 汇编代码

2.2.1 main函数汇编代码

<+0>:	push   %rbp
<+1>:	mov    %rsp,%rbp
<+4>:	sub    $0x30,%rsp
<+8>:	mov    %ecx,0x10(%rbp)
<+11>:	mov    %rdx,0x18(%rbp)
<+15>:	callq  0x40e780 <__main>
<+20>:	movl   $0x14,-0x4(%rbp)//栈中偏移4的空间初始化为20,即int a = 20
<+27>:	movl   $0x1e,-0x8(%rbp)//栈中偏移8的空间初始化为30,即int b = 30
<+34>:	lea    -0x8(%rbp),%rdx//取b的地址传给rdx
<+38>:	lea    -0x4(%rbp),%rax//取a的地址传给rax
<+42>:	mov    %rax,%rcx //rax的值传给rcx,即a的地址保存到rcx中
<+45>:	callq  0x401530 <swap(int&, int&)>//引用传参的函数
<+50>:	mov    $0x0,%eax
<+55>:	add    $0x30,%rsp
<+59>:	pop    %rbp
<+60>:	retq   

        由上图可知:

(1)main函数在栈中开辟了两个4字节空间,分别分配给a和b,并且分别初始化为20和30

<+20>:	movl   $0x14,-0x4(%rbp)//栈中偏移4的空间初始化为20,即int a = 20
<+27>:	movl   $0x1e,-0x8(%rbp)//栈中偏移8的空间初始化为30,即int b = 30

(2)准备传给swap函数的参数

<+34>:	lea    -0x8(%rbp),%rdx//取b的地址传给rdx
<+38>:	lea    -0x4(%rbp),%rax//取a的地址传给rax
<+42>:	mov    %rax,%rcx //rax的值传给rcx,即a的地址保存到rcx中
<+45>:	callq  0x401530 <swap(int&, int&)>//引用传参的函数

        swap函数的参数分别保存在rcx和rdx中,且是参数地址。

2.2.2 swap函数汇编代码

<+0>:	push   %rbp
<+1>:	mov    %rsp,%rbp
<+4>:	sub    $0x10,%rsp
<+8>:	mov    %rcx,0x10(%rbp)//a的地址保存到栈中(对应形参x)
<+12>:	mov    %rdx,0x18(%rbp)//b的地址保存到栈中(对应形参y)
<+16>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+20>:	mov    (%rax),%eax//a的值赋给eax(4字节)
<+22>:	mov    %eax,-0x4(%rbp)//eax的值赋给栈偏移为4的变量tmp中,即tmp = a
<+25>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+29>:	mov    (%rax),%edx//b的值赋给edx(4字节)
<+31>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+35>:	mov    %edx,(%rax)//eax的值赋给a,即a = b
<+37>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+41>:	mov    -0x4(%rbp),%edx//edx = tmp
<+44>:	mov    %edx,(%rax) //b = edx,即b = tmp
<+46>:	add    $0x10,%rsp
<+50>:	pop    %rbp
<+51>:	retq   

 由上图可知:

(1)swap函数接收了a和b变量的地址

<+8>:	mov    %rcx,0x10(%rbp)//a的地址保存到栈中(对应形参x)
<+12>:	mov    %rdx,0x18(%rbp)//b的地址保存到栈中(对应形参y)

(2)直接交换a、b空间的值

<+16>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+20>:	mov    (%rax),%eax//a的值赋给eax(4字节)
<+22>:	mov    %eax,-0x4(%rbp)//eax的值赋给栈偏移为4的变量tmp中,即tmp = a
<+25>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+29>:	mov    (%rax),%edx//b的值赋给edx(4字节)
<+31>:	mov    0x10(%rbp),%rax//取出a的地址到rax中
<+35>:	mov    %edx,(%rax)//eax的值赋给a,即a = b
<+37>:	mov    0x18(%rbp),%rax//取出b的地址到rax中
<+41>:	mov    -0x4(%rbp),%edx//edx = tmp
<+44>:	mov    %edx,(%rax) //b = edx,即b = tmp

三.汇编对比

3.1 main函数对比

        如下图所示。除了swap函数的形式不同,其他完全一样。

579bc67d781b4e7fad95a3e767616c9a.png

 

3.2 swap函数对比

        如下图所示。它们的代码完全一样。

6e5782191b8e4a428cf4eeb31c8514a4.png

四.结论

(1)引用传参和指针传参的汇编实现是一样的。

(2)引用也是传递变量指针给swap函数。

(3)引用只是C++语言的语法糖,它本质上还是指针。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1583825.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

静态页面上传服务器无法显示css效果

今天做比赛的项目&#xff0c;把静态页面上传到服务器&#xff0c;发现外联的css文件的效果无法显示&#xff0c;一开始以为是路径问题&#xff0c;后面改了发现没有改变。 然后发现在浏览器上css文件中content-type: text/plain的问题 这才是正确的&#xff1a; 修改办法&…

水牛社:互联网赚钱秘籍,免费项目,你真敢要吗?

免费是最贵的。真正理解并使用这句话的只有少数人&#xff0c;今天在网上分享一下免费项目背后的逻辑&#xff0c;抛开现象&#xff0c; 本质是最重要的。 我从事互联网工作15年。不管是过去还是现在&#xff0c;总有人喜欢问有没有免费项目&#xff1f; 其实我平时懒得回答…

【智能算法】省时方便,智能算法统计指标——一键运行~

目录 1.常用统计指标2.参数统计检验3.结果展示4.自定义修改测试框架 1.常用统计指标 测试智能算法性能时&#xff0c;常常会用到以下5种常用指标&#xff0c;简单不赘述&#xff1a; 最优值、最差值、均值、中位数、标准差 2.参数统计检验 单纯依靠常用统计指标说服力不足&…

每天五分钟深度学习PyTorch:面对Tensorflow,为何我选择PyTorch

这篇专栏文章不是为了挑起tenserflow和pytorch中哪个更好&#xff0c;众所周知tensorflow诞生以来&#xff0c;已经成为最流行的深度学习框架&#xff0c;可以说github中大多数的深度学习代码实现是以tensorflow实现的&#xff0c;也就是说资源众多&#xff0c;社区强大&#x…

Platforms Jumping(贪心,处理策略)

文章目录 题目描述输入格式输出格式样例输入1样例输出1样例输入2样例输出2样例输入3样例输出3提交链接提示 解析参考代码 题目描述 有一条宽度为 n n n 的河流。河的左岸是 0 0 0 单元格&#xff0c;右岸是 n 1 n1 n1 单元格(更正式地说&#xff0c;这条河可以表示为一串从…

APP被DDoS攻击时,企业应该如何防护?

某平台遭到分布式拒绝服务攻击&#xff0c;大规模、持续性的攻击&#xff0c;导致平台的APP、网站的部分用户出现间歇性无法登录、加载失败或缓慢等情况。据了解&#xff0c;平台在一个月的时间内陆续遭受到近30次的网络攻击。在这段时间内&#xff0c;平台不断地接收到短时间、…

在Debian 12系统上安装Docker

Docker 在 Debian 12 上的安装 安装验证测试更多信息引言 在现代的开发环境中,容器技术发挥着至关重要的作用。Docker 提供了快速、可靠和易于使用的容器化解决方案,使开发人员和 DevOps 专业人士能够以轻松的方式将应用程序从一个环境部署到另一个环境。 Docker 的安装过程在…

稀碎从零算法笔记Day45-LeetCode:电话号码的字母组合

题型&#xff1a;映射、回溯算法、递归 链接&#xff1a;17. 电话号码的字母组合 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出…

python如何输入多行

Python中的Input()函数在输入时&#xff0c;遇到回车符&#xff0c;那么一次输入就结束了。这不能满足输入多行文本并且行数也不确定的情形&#xff0c;当然输入空行也是允许的。 方法1&#xff1a;利用异常处理机制实现 lines[] while True:try:lines.append(input())except:…

【Java基础题型】矩阵的对角线求和

一、题目-矩阵 求一个33矩阵对角线元素之和。 输入格式 矩阵 输出格式 主对角线 副对角线 元素和 样例输入 1 2 3 1 1 1 3 2 1 样例输出 3 7 二、参考的知识 这里给大家送点英语单词&#xff0c;记得学习&#xff1a; p r i m a r y. adj.主要的&#xff1b;初…

2024.4.8Morris中序遍历(线索二叉树)学习

这次博主在学习完知识点和代码之后&#xff0c;准备对这个知识重新进行整理总结。站在一个初学者的角度来看待这个知识点&#xff0c;在他人的讲解基础上加一点点自己的理解&#xff0c;并记录下来。以加深自己的理解&#xff0c;并且希望能够帮助到你。博主是一个初学者&#…

vue的监视属性

目录 1. 场景引入2. watch3. 深度监视4. 监视属性简写5. 小结 1. 场景引入 在实际开发中&#xff0c;有时开发者需要根据某个属性的变化&#xff0c;做出相应的决策&#xff0c;因此Vue为开发者提供了watch.这一监视属性&#xff0c;用于实现此类需求。比如下面这个场景&…

【muzzik 分享】原生预览调试!我给Cocos加了个新功能,原生开发者福音

前言 一年一度的征稿到了&#xff0c;倒腾点存货&#xff0c;在之前阅读云风大佬文章的时候&#xff0c;发现他的引擎调试机制是在 手机上实时刷新预览&#xff0c;而不是在PC上调试&#xff0c;作为一个 Cocos 原生开发者&#xff0c;我深有体会&#xff0c;主要有以下原因 C…

一、Spring基础 --- 基础内容(二) (咕P4)

一、IOC容器 1.1 基础 1.1.1 容器 1、Spring框架的主要功能是通过其核心容器来实现的。2、Spring容器是生成Bean的工厂&#xff0c;它负责创建Bean的实例&#xff0c;并管理其生命周期。所有的组件都被当成Bean处理&#xff0c;例如数据源、Hibernate的SessionFactory、事务管…

【Keil5-报错】

Keil5-报错 ■ 调试烧录出现问题■ 烧录程序失败■ 编译报错 .\Objects\stm32h7_tms.axf: Error: L6218E: Undefined symbol __heap_base (referred from alloc.o).■ Keil5 load 出错■ No Space in execution regions with .ANY selector matching startup ...■ Execution r…

寄快递的省钱小妙招,看看你能知道多少

首先就是从包裹的重量上和体积上&#xff0c;我们都知道快递员上门取件都是需要称重的&#xff0c;我们能做的就是尽量压缩包裹的体积来减少快递的运费价格。然后是使用自己的包装袋来打包行李&#xff0c;快递员的袋子也是需要另外花费的。对于一些不容易损坏的货物来说&#…

基于SVM的时间序列预测模型matlab代码

整理了基于SVM的时间序列预测模型matlab代码&#xff0c; 包含数据集。采用了四个评价指标R2、MAE、MBE、MAPE对模型的进行评价。SVM模型在数据集上表现非常好。 Mean squared error 0.000180613 (regression) Squared correlation coefficient 0.995639 (regression) Mea…

了解单链表

27. 移除元素 - 力扣&#xff08;LeetCode&#xff09; 思路一&#xff1a; 创建新的数组&#xff0c;遍历原数组&#xff0c;将不为val的值放到新数组当中。空间复杂度不为O(1) 思路二&#xff1a;双指针法 我们设置两个指针src&#xff08;源数据&#xff09;和dst&#xf…

MOS管的判别符号记忆与导通条件

参考链接 MOS管的判别与导通条件 (qq.com)https://mp.weixin.qq.com/s?__bizMzU3MDU1Mzg2OQ&mid2247520228&idx1&sn5996780179fbf01f66b5db0c71622ac3&chksmfcef6c86cb98e590e3d3734ee27797bdded17b6b648b3b0d3b1599e8a4496a1fa4e457be6516&mpshare1&…

[CUDA 学习笔记] 矩阵转置算子优化

矩阵转置算子优化 矩阵转置是一种基础的矩阵操作, 即将二维矩阵的行列进行反转. 本文主要围绕行主序的二维单精度矩阵的转置考虑相关的优化. 以下 kernel 笔者均是在 NVIDIA V100 (7.0 算力) 上进行测试的, 且选择矩阵的行列维度大小为 M2300 N1500. Version 0. 朴素实现 _…