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

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

一.函数通过指针传参

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++语言的语法糖,它本质上还是指针。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习300问】66、ReLU激活函数相对于Sigmoid和Tanh激活函数的优点是什么?ReLU它有局限性吗?如何改进?

一、ReLU相对于Sigmoid和Tanh的优点 &#xff08;1&#xff09;计算效率高 ReLU函数数学形式简单&#xff0c;仅需要对输入进行阈值操作&#xff0c;大于0则保留&#xff0c;小于0则置为0。Sigmoid和Tanh需要指数运算但ReLU不需要。所以相比之下它会更快&#xff0c;降低了神经…

agi入门-大模型开发基础

AGI(Artifical General Inteligence)的到来还有多久&#xff1f; 乐观预测&#xff1a;明年主流预测&#xff1a;3-5年悲观预测&#xff1a;10年 AGI时代&#xff0c;AI无处不在&#xff0c;相关从来者将如何分&#xff1f; AI使用者&#xff1a;使用别人开发的AI产品AI产品…

让链接直接唤起应用,Xinstall助力提升用户体验

在移动互联网时代&#xff0c;应用程序已成为我们日常生活的重要组成部分。然而&#xff0c;有时候我们在浏览器或其他应用中看到一个有趣的链接&#xff0c;想要打开对应的应用查看更多内容&#xff0c;却需要手动复制链接&#xff0c;再打开应用粘贴查看。这样的操作繁琐且不…

Backtrader 量化回测实践(6)——量化回测评价工具Quantstats

Backtrader 量化回测实践&#xff08;6&#xff09;——量化回测评价工具Quantstats 1.概述 Quantstats是用于量化金融分析和投资组合优化的Python库。该库提供了各种工具&#xff0c;可从不同来源获得金融数据&#xff0c;进行技术和基本分析&#xff0c;并创建和测试投资策…

VPP 负载均衡测试代码

1. 均衡的测试思想和流程说明。 先说一下理论&#xff0c; 然后后边才知道 代码逻辑。 调试了两天&#xff0c;这个代码终于通了。 由于时间关系&#xff0c; 画了一个粗略的图。另外这个代码只是流程通了&#xff0c;不过要帮助理解负载均衡我认为已经足够了。 下面是windo…

什么是企业邮箱?如何选择合适的企业邮箱?

企业邮箱和个人邮箱不同&#xff0c;它的邮箱后缀是企业自己的域名。企业邮箱供应商一般都提供手机app、桌面端、web浏览器访问等邮箱使用途径。那么什么是企业邮箱&#xff1f;如何选择合适的企业邮箱&#xff1f;好用的企业邮箱应具备无缝迁移、协作、多邮箱管理等功能。 企…

Docker篇(二)— Docker架构介绍

目录 一、Docker和虚拟机的区别二、Docker架构镜像和容器DockerHubDocker架构 小结 一、Docker和虚拟机的区别 Docker可以让一个应用在任何操作系统中非常方便的运行。而以前我们接触的虚拟机&#xff0c;也能在一个操作系统中&#xff0c;运行另外一个操作系统&#xff0c;保…

智能面试——录音及播放下载js-audio-recorder — post请求,formdata传参

录音插件 js-audio-recorder bug&#xff1a;本地调试调取不起来麦克风 浏览器配置安全域名 chrome://flags/Insecure origins treated as secure输入域名即可电脑需要连接上耳机 <template><div class"BaseRecorder"><div class"BaseRecorder-r…

产品开发流程

产品开发流程 时间&#xff1a;2024年04月10日 作者&#xff1a;小蒋聊技术 邮箱&#xff1a;wei_wei10163.com 微信&#xff1a;wei_wei10 产品开发流程_小蒋聊技术_免费在线阅读收听下载 - 喜马拉雅欢迎收听小蒋聊技术的类最新章节声音“产品开发流程”。时间&#xff1a;…

单链表专题

文章目录 目录1. 链表的概念及结构2. 实现单链表2.1 链表的打印2.2 链表的尾插2.3 链表的头插2.4 链表的尾删2.5 链表的头删2.6 查找2.7 在指定位置之前插入数据2.8 在指定位置之后插入数据2.9 删除pos节点2.10 删除pos之后的节点2.11 销毁链表 3. 链表的分类 目录 链表的概念…

设计模式学习笔记 - 设计模式与范式 -行为型:10.迭代器模式(中):遍历集合时,为什么不能增删集合?

概述 上篇文章&#xff0c;我们通过给 ArrayList 和 LinkedList 容器实现迭代器&#xff0c;学习了迭代器模式的原理、实现和设计意图。迭代器模式主要主要是解耦容器代码和遍历代码。 本章&#xff0c;我们来深挖一下&#xff0c;如果在使用迭代器遍历集合的同时增加、删除集…

无尘净化棉签:清洁革新的里程碑

随着科技的不断进步&#xff0c;日常生活中的许多小物件也在不断地得到创新和改良。其中&#xff0c;棉签作为一种常见的清洁工具&#xff0c;经历了从传统到现代的革新&#xff0c;引入了无尘棉签的概念&#xff0c;为清洁领域带来了一场革命性的变革。本文优斯特将探讨无尘棉…

运维工具-Backup集合

RepositoryLicenseStarCreatedAtUpdatedAtDescriptionjeessy2/backup-xMIT2842021-11-132023-12-15带Web界面的数据库/文件备份增强工具noovertime7/gin-mysqlbakMIT382022-06-212023-02-06一款分布式高性能的备份系统&#xff0c;支持 MySQL、ElasticSearch 备份&#xff0c;多…

《高通量测序技术》分享,生物信息学生信流程的性能验证,以肿瘤NGS基因检测为例。

这是这本书&#xff0c;第四章第五节的内容&#xff0c;这一部分是以NGS检测肿瘤基因突变为例&#xff0c;描述了其原理和大概流程&#xff0c;这和以前我分享的病原宏基因组高通量测序性能确认方案可以互相补充&#xff0c;大家可以都看一下&#xff0c;但是想要真正的弄懂&am…

【Leetcode】1702. 修改后的最大二进制字符串

文章目录 题目思路代码复杂度分析时间复杂度空间复杂度 结果总结 题目 题目链接&#x1f517; 给你一个二进制字符串 b i n a r y binary binary &#xff0c;它仅有 0 0 0 或者 1 1 1 组成。你可以使用下面的操作任意次对它进行修改&#xff1a; 操作 1 &#xff1a;如果…

背 单 词

单词&#xff1a; 买考研词汇闪过 研究艾宾浩斯遗忘曲线 https://www.bilibili.com/video/BV18Y4y1h7YR/?spm_id_from333.337.search-card.all.click&vd_source5cbefe6dd70d6d84830a5891ceab2bf9 单词方法 闪记背两排&#xff08;5min&#xff09;重复一遍&#xff08;2mi…

解决Can‘t connect to HTTPS URL because the SSL module is not available

把C:\develop\An3\Library\bin的这些文件&#xff0c;复制到C:\develop\An3\DLLs中

2006年重邮801信号与系统考研真题与详解

本系列文章为重庆邮电大学801信号与系统考研真题与详解&#xff0c;前面文章链接如下&#xff1a; 2003年重邮801信号与系统考研真题与详解 2004年重邮801信号与系统考研真题与详解 2005年重邮801信号与系统考研真题与详解 文章目录 前言一对一极速提分辅导2006年重邮801信号与…

基于GAN的图像补全实战

数据与代码地址见文末 论文地址:http://iizuka.cs.tsukuba.ac.jp/projects/completion/data/completion_sig2017.pdf 1.概述 图像补全,即补全图像中的覆盖和缺失部分, 网络整体结构如下图所示,整体网络结构还是采取GAN,对于生成器,网络结构采取Unet的形式,首先使用卷积…