上次的课中都是使用C代码生成汇编代码,这次课中将使用C++代码生成汇编代码,对比结果发现这两种语言最终生成的代码形式很像。


C语言版本:

void foo()
{int x;int y;x=11;y=17;swap(&x,&y);
}

对应的汇编代码:

SP=SP-8;
M[SP+4]=11;
M[SP]=17;
R1=SP;//&y
R2=SP+4;//&x
SP=SP-8;
M[SP]=R2;
M[SP+4]=R1;
CALL<swap>;
SP=SP+8;//与第6行代码抵消
SP=SP+8;//与第1行代码抵消
RET;

活动记录示意图:

注意:

1.Saved PC中关联着调用foo的函数的相关信息,在其他某个函数的汇编指令流中会有一条call foo指令,saved PC的值就是直接位于这条call指令之后的指令地址。

2.在函数内部,在返回之前栈指针需要指向刚刚进入函数时的位置(即指向saved PC)。

3.RET指令通常会在函数体生成汇编代码最后一行,用来返回函数返回值的。在函数返回时会把返回值保存到 RV寄存器中,改变PC的值为函数返回后一下条指令地址(保存在SP寄存器中),并开始执行。


C语言(指针)

void swap(int* ap,int* bp)
{int tmp;tmp=*ap;*ap=*bp;*bp=tmp;
}

对应的汇编代码:

<swap>:
SP=SP-4;
R1=M[SP+8];
R2=M[R1];//M[M[SP+8]]从概念上来说是可以这么做的,但实际上找不到能够支持在一条汇编代码指令中进行两层引用的计算机体系结构。
M[SP]=R2;//tmp=*apR1=M[SP+12];
R2=M[R1];//读取b的值
R3=M[SP+8];//读取a的值
R3=R2;//a=bR1=M[SP];
R2=M[SP+12];
M[R2]=R1;
SP=SP+4;
RET;

C++语言(引用)

void swap(int& a,int& b)
{int tmp;tmp=a;a=b;b=tmp;
}

注意:

当传递引用的时候,实际上传递的是指针,因此在实现中对于所有的引用的指针进行解引用操作。这里这个引用形式的swap函数和之前指针形式的swap函数的汇编代码完全一样,引用只是使用地址传递参数的另一种方式罢了,而且使用引用你就不必再接触&和*,编译器会根据你申明的这个函数,在每次引用变量a和b的时候为你找到a和b中实际存储的地址中对应的数据。

例子1:

int x=17;
Int y=x;
Int &z=y;

例子2:

int x=17;
Int y=x;
Int*z=&y;

这两个例子的活动记录都可以如图所示:

注意:

虽然从汇编角度来看,引用和指针是一样的,而且引用看起来更加方便。但是使用引用的话,一旦赋值就不能将引用重新绑定给新的左值(l-value),从上个例子来说,你不能将z重新与x绑定而放弃与y的绑定,也就是说你不能灵活的改变这个箭头指向的地址。但是对于指针来说是可以随便改变的。


抛开结构体和类的定义,只看底层实现的方式,结构体和类实际上是以完全相同的方式存储在内存中的。在C++中,结构体和类的唯一区别在于:对于类来说默认的访问修饰符是private,而对于结构来说默认的访问修饰符是public。因此编译器差不多将这两个语法结构等同对待。

class binky {public:private:int winky;char *blinky;char slinky[8};
};binky b;

内存结构示意图:

这就是变量b的内存结构,这种成员的放置方式和我们之前讲到的一样,成员的放置顺序也完全一样。


class fraction
{
public:fraction(int n , int d = 0);void reduce();//约分函数
private:static int gcd(int x. int y);//reduce的辅助函数
};

注意:

1.上述的辅助函数并不需要this指针(只需要比较两个整型数)。成员函数有static关键字,意味着调用它的时候,并不需要类的实例作为参数,可以将它当作一个单独的函数来使用,只不过它的作用域是在类的定义中的。静态方法由于不需要传递隐式的this指针,因此从内部实现被看作普通函数,可被成员函数调用。

2.static会影响继承使用特性,不能继承它,当继承类调用静态方法的时候,并不能得到正确的结果。所以类内一般都写非static成员函数,非static函数会根据类对象的不同有不同的反应,而static函数根据类不同有不同反应。


makefile命令或gcc命令流程:

1.调用预处理器:预处理器一般处理#define和#include命令;

2.调用编译器:编译器负责将.c文件.cc文件生成对应的.o文件,这些文件在输入make指令后就会在目录下生成。整个编译之后生成的是可执行文件,其中一个.o函数包含着main函数,在生成可执行文件之前还要链接;

3.调用链接器:链接器将一系列.o文件按顺序排列,并确保在执行过程中任何调用的函数都能从该函数所在的.o文件中找到;

4.生成a.out文件:其实就是所有a.out文件的打包整合。

注意:

汇编指令中的CALL<标号>指令,其实当链接结束后就会变成CALL<PC + 1234>这种形式,这样就可以根据PC的相对地址跳转到对应标号函数的开始地址了。因为所有的符号在可执行文件创建后都已经有了明确的地址,如果连接器知道每一个.o文件中的所有符号,以及这些.o文件是怎样顺序排列在一起的话,连接器就可以移除这些符号而用一个相对于PC的地址代替它。


预处理:

#define w 480
#define h 720
printf("widthis %d\n",w);
int area=w*h;

1.预处理器依次读入传入的.c文件的内容,只关心#符号开头的行。读到有#开头的行时候,预处理内部会有一个hashset,左边为key右边为value,存储着被定义过的名字。随着预处理器一行行读入代码,会把遇到的key(字符串常量中的除外)文本替换成value。

2.预处理器就是将一个.c文件内容读入,并将结果输出到同一个.c文件,但是去掉了#define和其他的预处理指令,所以经过预处理后就没有#define指令了(#define只是大规模的查找和替换,用来为常数或常量字符串赋予一个有意义的名字)。

3.在预处理阶段进行的都只是文本替换,结果作为数据传到下一阶段,预处理阶段并不进行类型检查,文本替换产生的问题会在之后的编译阶段进行识别。

编程范式(斯坦福大学)学习笔记《十一》相关推荐

  1. 编程范式(斯坦福大学)学习笔记《二》

    斯坦福大学开放课程:编程范式学习笔记<二> 本课讲述了C/C++关于int,float等数据的底层表示,以及赋值操作所进行的处理.本节内容比较简单,应该属于组成原理的基础知识,各种码的表示 ...

  2. 编程范式(斯坦福大学)学习笔记《四》

    斯坦福大学开放课程--编程范式(四) 综述 本节课的主要内容是关于泛型数据的拷贝,虽然是使用C语言实现,并且没有用到C++中的模板这种泛型编程技术,但是效果却非常好.本节内容紧接上节所将的字节位拷贝的 ...

  3. 编程范式(斯坦福大学)学习笔记《十二》

    本节课讲解的主要是预处理器,编译和连接的异同. #define有两个功能:一个是定义常量,一个是作为宏. //定义常量 #define w 40 #define h 80 #define pere 2 ...

  4. Netty学习笔记二网络编程

    Netty学习笔记二 二. 网络编程 1. 阻塞模式 阻塞主要表现为: 连接时阻塞 读取数据时阻塞 缺点: 阻塞单线程在没有连接时会阻塞等待连接的到达,连接到了以后,要进行读取数据,如果没有数据,还要 ...

  5. NVIDIA可编程推理加速器TensorRT学习笔记(二)——实操

    NVIDIA可编程推理加速器TensorRT学习笔记(二)--实操 ​ TensorRT 是 NVIDIA 自家的高性能推理库,其 Getting Started 列出了各资料入口,如下: 本文基于博 ...

  6. css中怎么加入立体模型,CSS学习笔记二:css 画立体图形

    继上一次学了如何去运用css画平面图形,这一次学如何去画正方体,从2D向着3D学习,虽然有点满,但总是一个过程,一点一点积累,然后记录起来. Transfrom3D 在这一次中运用到了一下几种属性: ...

  7. wxpython应用程序对象与顶级窗口_wxPython学习笔记(二)

    如何创建和使用一个应用程序对象? 任何wxPython应用程序都需要一个应用程序对象.这个应用程序对象必须是类wx.App或其定制的子类的一个实例.应用程序对象的主要目的是管理幕后的主事件循环. 父类 ...

  8. NumPy学习笔记 二

    NumPy学习笔记 二 <NumPy学习笔记>系列将记录学习NumPy过程中的动手笔记,前期的参考书是<Python数据分析基础教程 NumPy学习指南>第二版.<数学分 ...

  9. qml学习笔记(二):可视化元素基类Item详解(上半场anchors等等)

    原博主博客地址:http://blog.csdn.net/qq21497936 本文章博客地址:http://blog.csdn.net/qq21497936/article/details/7851 ...

最新文章

  1. 11gR2 GI和DB安装目录权限属主被修改后的恢复方法
  2. exfat 分配单元大小_知到金融理论与实务第一单元章节测试答案
  3. IBM确定公司未来存储技术发展方向
  4. 教你在64位Win7系统下使用ObRegisterCallbacks内核函数来实现进程保护
  5. 是AI就躲个飞机-纯Python实现人工智能
  6. 安徽省公务员计算机专业知识,安徽省公务员考试计算机专业知识编程题
  7. PHP上传方式base64图片的接收方式
  8. BZOJ2938: [Poi2000]病毒(AC自动机)
  9. 【经典回放】多种语言系列数据结构算法:二叉树(JavaScript版)
  10. endp 汇编start_飞思卡尔Kinetis L 汇编语言启动文件startup_MK25Z4简单分析
  11. Algs4-1.4.18数组的局部最小元素
  12. gin 静态文件服务器拒绝,nginx实现简单的图片服务器(windows)+静态文件服务器-Go语言中文社区...
  13. elasticsearch内部版本控制
  14. json:JSONObject包的具体使用(JSONObject-lib包是一个beans,collections,maps,java arrays和xml和JSON互相转换的包)...
  15. ambari安装的各组件的目录
  16. Linux socket等于0,Linux系统环境下的Socket编程详细解析
  17. Java(TM) Platform SE binary已停止工作
  18. 微信安装正确操作方法
  19. 将oracle端口1521共享_[转]利用oracle1521端口抓鸡
  20. MATLAB中的resample函数根本理解,我专栏中有Guitar.MAT资源

热门文章

  1. win7安装office 2010错误解决方案
  2. 电子电路之三极管封装
  3. 数据结构与算法看这篇就够了
  4. 云看大熊猫,动物园如何利用视频技术玩转动物IP?
  5. SQL创建-----表
  6. python 经验模态分解_经验模态分解下的日内趋势交易策略 附源码
  7. [Errno 13] Permission denied:解决办法
  8. 零基础无实物一步一步学PLCS7-1200仿真 背景知识一 低压元器件基础
  9. 【华为OD机试真题 python】最大股票收益【2022 Q4 | 100分】
  10. pb调用http的简单方法