从编译器角度理解C++中的引用和指针
欲分析指针和引用,则要分析变量名和地址之间的关系(不管你理解还是不理解,无论你是从老师那里听到的,还是网上看到的,应该都知道两句话:1、 指针就是地址,2、引用就是给变量起个别名)
所以我们就要来分析分析变量名和地址之间的关系。这就要从编译原理中的符号表说起,我们上编译原理的时候老师就没有将那一章,所以对于符号表,我的认识比较浅显,不过应该已经能够解释地址和变量名之间的关系啦。
编译器中通常要维护一个符号表,而且这个符号表是要贯串整个编译过程的。网上盗了张图

如果没有学过编译原理,看不懂这张图也没有关系,只需要知道,编译器维护了一张符号表,而且这个表贯串整个编译过程就好。
这张表有什么用呢? 我也说不太明白(老师没讲,自己也懒得看书,大家不要学我,学好专业基础课很重要!很重要!很重要!重要的话说三遍)
还是网上找的一个解释:(懒得看可以忽略)
符号表在编译程序工作的过程中需要不断收集、记录和使用源程序中一些语法符号的类型和特征等相关信息。这些信息一般以表格形式存储于系统中。如常数表、变量名表、数组名表、过程名表、标号表等等,统称为符号表。对于符号表组织、构造和管理方法的好坏会直接影响编译系统的运行效率。
在编译过程中需要不断汇集和查证出现在源程序中的各种名字的属性和特征等信息编译器使用符号表来记录名字的作用域以及绑定信息编译程序中符号表用来存放语言程序中出现的有关标识符的属性信息,符号表中的信息在编译的不同阶段都用到在语义分析中,符号表所登记的内容将用于语义检查(如检查一个名字的使用和原先的说明是否一致)和产生中间代码在目标代码生成阶段,当对符号名进行地址分配时,符号表是地址分配的依据。对一个多遍扫描的编译程序,不同遍所用的符号表也往往各有不同。因为每遍所关心的信息各有差异。
下面是一张貌似是pascal语言编译器中的符号表(可以不看,有个大概印象就行)

下面我们简化出一个符号表,专门用来解释变量名和地址之间的关系(重要,必须看)
假设我们定义了一个变量a :
int a = 10;
在编译器的编译的某个阶段(随着编译的进行,符号表是不断变化的)有如下符号表(我自己简化的,实际并不长这个样子)
|
变量名 |
首地址 |
类型 |
空间大小 |
值 |
|
a |
0x3333 |
int |
4字节 |
10 |
那么当我们将a++时,编译器会查找符号表,找到变量名为a的条目(符号表本质上就是一个表格,或者说是一个数据库),找到之后,根据a的首地址、类型、值等将a的值变为11
编译器将代码翻译成机器代码后,是没有变量名的,学过汇编的都知道,汇编语言都是直接操作地址的,根本没有变量名。
所以变量名可以理解为编译器符号表的一个索引,我们再做a++运算时,实际上编译器是根据变量名a找到了我们要操作的内存的首地址,然后在根据符号表中记录的属性,对该内存区域进行操作。
所以说变量名可以理解为地址的索引,或者说变量名代表了符号表中的一行。这一行中不进有首地址,还有类型、空间大小、值等。
所以我们要找到变量的地址需要用&(取地址)符号。(当然对于数组是不需要的)
所以我们可以这样说,变量名可以理解为被各种属性修饰的地址(这里的属性指类型、空间大小、值等)。进一步,变量名可以理解为一个受限制的地址(首各种属性的限制)
我们知道指针变量中存储的就是符号表中,某一行的首地址字段。然而只有这个首地址,没有那些属性(其他字段的限制),我们能做的事情就会很多:
我们可以人为的给这个首地址分配内存空间(malloc函数)、我们可以人为地给这个地址空间设定访问规则为按double类型访问(malloc时,强制类型转换成double),这也就是说我们可以人为规定首地址的类型和空间大小等属性
这也是指针的强大之处,指针中存的就是首地址,而这个首地址的各种属性都可以由程序员决定。
对吧!
但是通过变量名,我们可以访问到的地址是受限制的,因为在我们写int a= 10的时候,a的地址空间的大小、类型等都是编译器为我们分配和决定的!我们没有权利去做。但是通过声明一个指针,我们就可以自己决定这篇内存的属性!!!!
这也就是指针的强大之处,也是它的可怕之处。
所以一句话总结一下变量名和地址的关系就是:变量名可以理解为一个受各种属性限制的地址(而这些属性,是编译器决定的),指针就是地址,创建一个指针,就是创建一个不受各种属性限制的地址!!
再来说引用,引用就是变量的一个别名字,那我们写,比如int &b = a;这个时候编译器的符号表中就会多一个条目:
|
变量名 |
首地址 |
类型 |
空间大小 |
值 |
|
b |
0x3333 |
int |
4字节 |
10 |
发现没有,除了变量名不一样,其他的都一样!!!所以a和b就是一个东西
那么可以说,引用和指针的区别,就是变量名和指针的区别,进一步简单理解为变量名和首地址的区别!!!!
是我自己的一些想法,有些知识可能存在不准确和错误。。。尽请谅解。。。。
从编译器角度理解C++中的引用和指针的更多相关文章
- IL角度理解C#中字段,属性与方法的区别
IL角度理解C#中字段,属性与方法的区别 1.字段,属性与方法的区别 字段的本质是变量,直接在类或者结构体中声明.类或者结构体中会有实例字段,静态字段等(静态字段可实现内存共享功能,比如数学上的pi就 ...
- 多态原理探究-从C++编译器角度理解多态的实现原理
理论知识: 当类中声明虚函数时,编译器会在类中生成一个虚函数表. 虚函数表是一个存储类成员函数指针的数据结构. 虚函数表是由编译器自动生成与维护的. virtual成员函数会被编译器放入虚函数表中. ...
- c++中的引用与指针的区别
http://blog.csdn.net/lyd_253261362/article/details/4323691 c++中的引用与指针的区别 ★ 相同点: 1. 都是地址的概念: 指针指向一块内存 ...
- 理解Java中的引用传递和值传递
关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天学习 ...
- (转载)理解Java中的引用传递和值传递
关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天 ...
- [ZZ]C++中,引用和指针的区别
(1) 引用总是指向一个对象,没有所谓的 null reference .所有当有可能指向一个对象也由可能不指向对象则必须使用 指针. 由于C++ 要求 reference 总是指向一个对象所以 re ...
- 【C++】C++中的引用与指针
想必大家对C++中的指针都有所了解,但是什么是引用呢?C++11标准引入了“引用”的新功能. 引用 引用(reference):给对象起了另外一个名字,引用类型引用(refers to)另外一种类型, ...
- C中有关引用和指针的异同
参考于https://blog.csdn.net/wtzdedaima/article/details/78377201 C语言也学了蛮久的,其实一直都没有用到过或者碰到过引用的例子.前端时间再全面复 ...
- 使用java实现单链表----(java中的引用就是指针)
//一直以为java中没有指针,其实java的引用就是指针,只不过堆栈中的引用储存了在堆中的地址,可以看做java中的指针.public class sibgleLink<E> { // ...
随机推荐
- 小练习,判断X的奇偶性
package lianxi1; public class text { public static void main(String[] args) { ; ==) { System.out.pri ...
- 老李推荐: 第3章2节《MonkeyRunner源码剖析》脚本编写示例: MonkeyDevice API使用示例 4
第七步:保存新增加日记 代码3-2-7 增加日记-保存日记 #Step7: Save the note by touch on the "save" menu entry by c ...
- Gym 101257G 24 (概率+二分)
题意: 有一道分值为sa的题,n个人比赛写这道题,按照递减的顺序给出每个人的当前分数,和每个人写不出这道题的概率,让你输出有反超现象出现的期望 思路:由于之前把题目翻译错了导致很久没有相通,后来看了别 ...
- oracle的insert的时候&符号如何插入(转义)
chr(38)替换& insert into table values( 'http://localhost:8080/index.action?username=138& ...
- JavaScript基础学习(一)—JavaScript简介
一.JavaScript概述 JavaScript是一种专为与网页交互的脚本语言,由三部分组成. ECMAScript 核心,提供核心语言功能. BO ...
- 基于Spring开发——自定义标签及其解析
1. XML Schema 1.1 最简单的标签 一个最简单的标签,形式如: <bf:head-routing key="1" value="1" to= ...
- WebGL 创建和初始化着色器过程
1.编译GLSL ES代码,创建和初始化着色器供WebGL使用.这些过程一般分为7个步骤: 创建着色器对象(gl.createBuffer()); 向着色器对象中填充着色器程序的源代码(gl.shad ...
- C#基础语法(一)
一.基础语法 1.C#区分大小写,所以myVar和MyVar是两个不同的变量. 2.每个C#可执行文件(如控制台应用程序,Windows应用程序和Windows服务)都必须有一个入口点----Main ...
- 什么是javascript的回调函数?
回调函数(callback) 基本上每本书里都会提一提实际上我们几乎每天都在用回调函数,那么如果问你到底什么是回调函数呢? 1. 回调函数是作为参数传递给另一个函数 2. 函数运行到某种程度时,执行回 ...
- 介绍三个Android支持库控件:TabLayout+ViewPager+RecyclerView
本文主要介绍如下三个Android支持库控件的配合使用: TabLayout:android.support.design.widget.TabLayout ViewPager:android.sup ...