c++为我们所提供的各种存取控制仅仅是在编译阶段给我们的限制,也就是说是编译器确保了你在完成任务之前的正确行为,如果你的行为不正确,那么你休想构造出任何可执行程序来。但如果真正到了产生可执行代码阶段,无论是c,c++,还是pascal,大家都一样,你认为c和c++编译器产生的机器代码会有所不同吗,你认为c++产生的机器代码会有访问限制吗?那么你错了。什么const,private,统统没有(const变量或许会放入只读数据段),它不会再给你任何的限制,你可以利用一切内存修改工具或者是自己写一个程序对某一进程空间的某一变量进行修改,不管它在你的印象中是private,还是public,对于此时的你来说都一样,想怎样便怎样。另外,你也不要为c++所提供的什么晚期捆绑等机制大呼神奇,它也仅仅是在所产生的代码中多加了几条而已,它远没有你想象的那么智能,所有的工作都是编译器帮你完成,真正到了执行的时候,计算机会完全按照编译器产生的代码一丝不苟的执行。(以下的反汇编代码均来自visial c++ 7.0) 一.让我们从变量开始-----并非你想象的那么简单变量是什么,变量就是一个在程序执行过程中可以改变的量。换一个角度,变量是一块内存区域的名字,它就代表这块内存区域,当我们对变量进行修改的时候,会引起内存区域中内容的改变。但是你若是学习过汇编或是计算机组成原理,那么你就会清楚对于一块内存区域来说,根本就不存在什么名字,它所仅有的标志就是他的地址,因此我们若想修改一块内存区域的内容,只有知道他的地址方能实现。看来所谓的变量一说只不过是编译器给我们进行的一种抽象,让我们不必去了解更多的细节,降低我们的思维跨度而已。例如下面这条语句:
int a=10;
按照我们的思维习惯来讲,就是“存在一个变量a,它的值是10”,一切都显得那么的自然。我们不必去在乎什么所谓的地址以及其他的一些细节。然而在这条语句的底层实现中,a已经不能算是一个变量了,它仅仅是一个标记,代表一个地址的标记:
mov dword ptr[a],0Ah;
怎么样,这条语句不像上面那条易于接受吧,因为它需要了解更多的细节,你几乎不能得到编译器的任何帮助,一切思维上的跨越必须由你自己完成。这条语句应该解释为“把10写入以a为地址的内存区域”。你说什么?a有些像指针?对,的确像,但还不是,只不过他们的过程似乎是类似的。这里所说的跨越实际上就是从一个现实问题到具体地址以及内存区域的跨越。
二.引用:你可以拥有引用,但编译器仅拥有指针(地址)
看过了第一条,你一定对编译器的工作有了一定的了解,实际上编译器就是程序员与底层之间的一个转换层,它把一个高级语言代码转换为低级语言代码,一个编译器完成的转换跨度越大,那么它也就会越复杂,因为程序员的工作都由他代为完成了。C++编译器必然比汇编编译器复杂就是这个道理。如果我问你引用和指针是一样的吗?你或许会说当然不一样了,指针容易产生不安全的因素,引用却不会,真的不会吗?我们来看下面这段代码:
int *e=new int(10);
int &f=*e;
delete e;
f=30;你认为上面这段代码怎么样,我感觉就不很安全,它和指针有相同的隐患。因为它所引用的内存区域就不合法。我个人认为,所谓的引用其实就是一种指针,只不过二者的接口并不相同,引用的接口有一定的限制。指针可以一对多,而引用却只能一对一,即&refer不能被改变,但却并不能说一对一就是安全的,只不过危险的系数降低罢了。引用比指针更容易控制。
Ok,下面来说说指针,曾经有过汇编经验的人一定会说,恩,指针的某些地方有些像汇编,尤其是那个“*”,怎么就那么像汇编中的“[]”啊。的确,它也涵盖了一个寻址的过程。看来指针的确是个比较低级的东西。然而引用却并不那么直接,虽然程序员用起来方便安全了许多。但是你要清楚,只有你可以拥有引用,编译器可没有这个工具,计算机并不认识这个东西。因此,它的底层机制实际上是和指针一样的。不要相信只有一块内存拷贝,不要认为引用可以为你节省一个指针的空间,因为这一切不会发生,编译器还是会把引用解释为指针。不管你相不相信,请看下面这段代码:int& b=a;
lea eax,[a];
mov dword ptr[b],eax;把a的地址赋给地址为b的一块内存
b=50;
mov eax,dword ptr[b];
mov dword ptr[eax],32h;
int *d=&a;
lea eax,[a];
mov dword ptr[d],eax
*d=60;
mov eax,dword ptr[d]
mov dword ptr[eax],3ch;以上的代码均来自具体的编译器,怎么样,相信了吧,好,让我再来做一个或许不怎么恰当的比拟,你一定编过有关线性表和栈的程序吧,线性表是一个非常灵活的数据结构,在他上面有许多的操作,然而栈呢,它是一个限制性操作的线性表,它的底层操作实际上是由线性表操作实现的。就好比stack与vector的关系,因此指针和引用的关系就好比线性表和栈的关系,引用也就是受限的指针,它对外的接口和指针虽然并不一样,但底层是相同的。下面再来看看引用的一个重要用途,作为函数的参数传递的时候是怎样的情形:
void swapr(int &a, int &b);
void swapr(int* a, int *b);
int a=10;
int b=20;
swapr(a, b);
lea eax,[a];
push eax; //把a的地址压入堆栈
lea ecx,[b];
push ecx;
call swapr;
swapr(&a, &b);
lea eax,[a];
push eax;
lea ecx,[b];
push ecx;
call swapr;怎么样,用引用和指针传递参数无论是在效率上还是在空间上都是完全一样的,如果妄想不传入地址就修改实参的值,简直就是天方夜谭,这就说明引用的本质就是指针。毕竟它们的行为都太相似了,如果不是这样,你还有什么方法去实现引用吗?记住,引用只不过是编译器为你提供的一个有用且安全的工具,对于机器代码可无法表示它,它把指针一对多的缺点去除,禁止了你的不安全的操作。但回到问题的本源,他们没有任何区别。
相关推荐
深度探索C++对象模型笔记
一、关于对象C 语言是程序性的,语言本身并没有支持数据和函数之间的关联性C++ 中可能采取抽象数据类型,或者是多层次的类结构完成C++ 的封装并没有增加多少成本,每一个成员函数虽然在cla...
探索c++的底层机制
在看这篇文章之前,请你先要明白一点:那就是c++为我们所提供的各种存取控制仅仅是在编译阶段给我们的限制,也就是说是编译器确保了你在完成任务之前的正确行为,如果你的行为不正确,那么你休想构造出任何可执行程序来。但如果真正到了产生可执行代码阶段,无论是c,c++,还是pascal,大家都一样,你认为c和c++编译器产生的机器代码会有所不同吗,你认为c++产生的机器代码会有访问限制吗?那么你错了。什么c
手把手教你用ADS仿真FMMT417雪崩三极管,搞定射频脉冲源设计
本文详细介绍了如何使用ADS仿真工具设计基于FMMT417雪崩三极管的射频脉冲源。从器件选型、SPICE模型导入到电路设计与优化,提供了一套完整的实操方案,特别适合射频脉冲设计的初学者。通过级联设计和实测验证,帮助工程师快速掌握雪崩电路的应用技巧,提升射频脉冲源的设计效率。
C++ 引用的本质是什么?
结论: ①C++中的引用本质上是 一种被限制的指针(类似于线性表和栈,栈是被限制的线性表,底层实现相同,只不过逻辑上的用法不同而已)。 ②由于引用是被限制的指针,所以引用是占据内存的。 ③在使用高级语言的层面上,是没有提供访问引用的方法的。并且引用创建时必需初始化,创建后还不能修改。 下面是找到的相关资料,来证明以上结论。 ************************************************************************************
ESP32锂电池电量检测实战:从引脚选择到低功耗优化(附完整电路图)
本文详细介绍了ESP32锂电池电量检测的实战方案,从ADC引脚选择到低功耗优化,提供完整的电路图和代码实现。通过MOS管智能开关和深度睡眠技术,显著降低静态功耗至0.5μA,提升设备续航能力。适合物联网开发者解决电量检测中的常见问题。
C++ —— 理解引用及其原理
概念 引用的简单概念: 引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共用同一块内存空间。 引用一般被使用做参数/返回值这样可以提高效率, 减少拷贝。 底层实现 在语言层面引用是一个对象的别名不占据空间, 但是实际上在底层的实现上引用是类似于指针实现的。 我们借助代码进行探索 int i=5; int &ri=i; ri=8; 通过:调试->窗口->反汇编 int i=5; 00A013DE mov dword
Windows 10/11蓝屏急救:SECURE_PCI_CONFIG_SPACE_ACCESS_VIOLATION报错全攻略(附安全模式+CMD修复)
本文针对Windows 10/11系统常见的SECURE_PCI_CONFIG_SPACE_ACCESS_VIOLATION蓝屏报错,提供了从诊断到修复的完整解决方案。文章深入剖析了该错误与系统安全功能“内存完整性”及pci.sys驱动的关系,并详细指导用户如何通过安全模式进行基础修复,以及使用命令提示符执行高级系统文件修复和注册表修改,帮助用户彻底解决蓝屏问题并恢复系统稳定。
【【C++笔记一】】
C++头文件、命名空间、C++:输入输出、类型增强、默认参数、函数重载、引用、isLonger()字符串比较函数 写在最后
【ComfyUI】Animate 保留原视频背景角色替换视频生成
本文介绍了智能创作与视频生成的工作流设计,强调其作为围绕业务目标、数据流转和模型能力的有机整体。工作流由数据输入、模型处理、结果合成和输出展示构成,通过节点化连接实现高效复用与扩展。文章重点解析了核心模型(如CLIP Vision、WanVideo等)的功能和协作方式,以及各类节点(输入、处理、控制、输出)的作用。最后展示了工作流在视频角色替换、虚拟试衣等场景的应用价值,并提供了相关开发资源链接。该设计通过模块化实现了灵活适配不同业务需求的能力。
TC3XX - MCAL知识点(二十):CAN MCAL配置及代码实战(CAN/CANFD/extenen CAN)
CAN驱动程序负责提供AUTOSAR指定的标准CAN通信服务。M_CAN单元是底层的CAN硬件单元,它由共享消息RAM(在AUTOSAR中称为硬件对象)的节点(在AUTOSAR中称为控制器)组成。CAN驱动提供以下服务:·初始化CAN控制器以控制CAN控制器的行为和状态·设置和修改CAN控制器的波特率配置·支持CAN和CAN FD帧的收发·在轮询和中断模式下,成功的帧传输通知,专用和FIFO消息的接收和总线事件通知·数据接收使用接收FIFO功能·假装网络模式处理·支持多读/写周期功能。
失落的指针C++重构记忆深渊
的姿态闯入堆内存的荒野时,代码便悄然分裂成两个世界:符号表里优雅的语法与物理地址中裸露的字节流开始展开隐秘的对话。每个`->`符号都是通往未知的入口,而`delete`的缺失会让内存泄漏如同地底暗河,直到某天洪水漫过代码的河床。`dynamic_cast`在对象图谱中投射的光线暗示着类型宇宙的弯曲几何,而`std::any`的`bad_any_cast`则是这些时空扭曲触发的观测者效应。局部作用域的生存期像希腊神话中的俄尔甫斯,一旦跨过`}`符号的冥河,所有手动管理的资源都可能腐朽成未被释放的幽灵。
OpenOCD入门到精通:第 0 章 教程导读
摘要:本教程是OpenOCD嵌入式调试工具的完整指南,适合从新手到资深工程师的学习需求。内容涵盖基础配置、调试技巧、Flash编程、TCL脚本自动化、源码解析和二次开发,共8大部分30章。教程提供5种学习路线,可根据角色和目标灵活选择,配套资源包含示例代码和配置文件。通过系统学习,读者将掌握OpenOCD从使用到扩展的全套技能,成为嵌入式调试领域的专家。
linux 共享内存_盘点那些linux 后台开发类常见问题及知识点
一、linux和os:netstat :显示网络状态tcpdump:主要是截获通过本机网络接口的数据,用以分析。能够截获当前所有通过本机网卡的数据包。它拥有灵活的过滤机制,可以确保得到想要的数据。ipcs:检查系统上共享内存的分配ipcrm:手动解除系统上共享内存的分配 (如果这四个命令没听说过或者不能熟练使用,基本上可以回家,通过的概率较小 ^_^ ,这四个命令的熟练掌握程度基本上能体现面试者...
任务混部最少服务器数量计算问题
这里的并行度指的是该任务运行时会占用的服务器数量。要注意的是,一个服务器在每个时刻可以被任意任务使用,但同一时刻最多只能被一个任务占用,并且任务运行结束后会立即释放服务器(结束时刻不占用)。最后,我们从字典中找出服务器数量的最大值,这个最大值就是完成这批任务混部最少需要的服务器数量。对于每个任务,我们会遍历其对应的时间区间,将该任务的并行度累加到对应时刻的服务器数量上。任务混部的目标是让这批任务由同一批服务器承载运行,你需要计算完成这批任务混部最少需要多少服务器,以此来最大化控制资源成本。
ET2012新版免狗免安装绿色软件
ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,
探秘地下城:OpenDungeons——开源策略游戏新星
探秘地下城:OpenDungeons——开源策略游戏新星 去发现同类优质开源项目:https://gitcode.com/ 项目介绍 OpenDungeons,这是一个基于Dungeon Keeper和Evil Genius系列元素的开源实时战略游戏。在游戏中,玩家将在地底世界建造属于自己的地下城,招募并指挥各类生物,与对手进行激烈的地盘争夺战。经过超过六年的开发,OpenDungeons已经发展...
计算机控制技术及应用
《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。
linux 后台开发类常见问题及知识点
一、linux和os: netstat :显示网络状态 tcpdump:主要是截获通过本机网络接口的数据,用以分析。能够截获当前所有通过本机网卡的数据包。它拥有灵活的过滤机制,可以确保得到想要的数据。 ipcs:检查系统上共享内存的分配 ipcrm:手动解除系统上共享内存的分配 (如果这四个命令没听说过或者不能熟练使用,基本上可以回家,通过的概率较小 ^_^ ,这四个命令的熟练掌握程度基本上能体现
jdk-8u144-linux-x64.tar.gz.
该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包
大中型超市收银系统(可直接运行)
光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开
找工作必备知识
一、C ①基本函数实现 swap() reverse() strcpy() ②五个存储区 ③内存对齐 ④数组名问题 int a[10]; int *p=a; p++;p+1;a+1; a++;//错误,数组名是常量 二、C++ ①static的作用 ②const的作用 ③四个类型转换 static_cast dynamic_cast const_cast re
找工作?该复习了!(转)
摘自:http://www.cnblogs.com/hanxi/archive/2012/11/04/2753993.html 我把我找工作中遇到的知识点统计了下,并归类了下,希望可以帮到正在找工作的童鞋们! 如果觉得有需要增加的可以添加到评论中,方便其他园友复习。 一、C ①基本函数实现swap()reverse()strcpy()②五个存储区③内存对齐④数组名问题int a[10];i...
烽火通信 c语言 笔试,C语言嵌入式笔试题目及参考答案-烽火通信.doc
C语言嵌入式笔试题目及参考答案-烽火通信.doc什么是预编译预编译又叫预处理,做一些编译前的准备工作,常见的有文件包含include代码重用,结构清晰、宏定义define(定义常量) 、条件编译if/elseif/else/endif ifdef/ifndef/endif ifndef/define/endif(避免头文件重复定义)提高编译效率。何时需要预编译、总是使用不经常改动的大型代码体。 、...
UE4/UE5角色移动防穿透:碰撞体、根组件与移动系统的协同原理与实践
在游戏开发中,碰撞检测是保障角色与环境交互真实性的核心技术。其原理是通过为角色赋予一个不可见的物理体积(碰撞体),与场景中的其他碰撞体进行几何检测,从而决定移动是否被阻挡。这项技术的核心价值在于构建可信的物理交互,是角色移动、战斗判定、物理模拟等功能的基础。在虚幻引擎(UE4/UE5)中,Pawn(可操控角色)的碰撞体系尤为关键,它依赖于碰撞体、根组件与移动组件三者的精密协作。一个常见但易被忽视的工程实践是:必须将主碰撞体(如胶囊体)设置为角色的根组件。这是因为移动系统进行扫掠检测时,默认以根组件的位置和形
1812



被折叠的 条评论
为什么被折叠?



