# 斯坦福编程范式 CS107_9

# C 语言与汇编语言的对照

int i =10;
int j =i+7;
j++;

上述代码在汇编中的形式为:

M[R1+4] = 10;		//store operation
R2 = M[R1+4];		//load operation
R3 = R2 + 7;		//ALU operation
M[R1] = R3;			//store operation
R2 = M[R1];
R2 = R2 + 1;
M[R1] = R2;

大写的 M 代表整个 RAM,将整个 RAM 看作是一个非常大的字节数组,R1 存储的是基地址,4 是偏移量。意思是,从基地址开始的四个字节写入数据 10。R1 存储的是 j 的地址。

image-20231118153659076

有人可能会问,“为什么不直接使用 M [R1]++”。因为在汇编语言中不允许直接对地址中的值进行修够,必须先通过 load operation 将其装载到寄存器中,对寄存器进行操作,并再将结果写回内存,这会使汇编语言更加简单,指令简单则时钟频率更快。

# 下面举一个不是 4 字节变量的例子:

int i;
short s1;
short s2;
i = 200;  
s1 = i;	
s2 = s1 + 1;

image-20231118154657047

M[R1+4] = 200;	

对于 s1 = i 如果不可以直接用一下汇编语言实现

M[R1+2] = M[R1+4]; //这样翻译是错误的,因为汇编语言中,load 和 store 不能同时进行

也不可以用以下方法,因为 short 类型只有 2 字节,当被赋值 R2 这 4 个字节时,4 字节数据会被传输给 s1,s1 将会是 0(因为 R2 的高二位字节为 0),而 i 会变成一个非常大的数(因为 i 的高二位字节被分别赋值为了 0 和 200)。

R2 = M[R1+4];	
M[R1+2] = R2;

需要修改为:

R2 = M[R1+4];	
M[R1+2] = .2 R2; //移动两个字节,而不是4个

对于 s2 = s1 + 1; 汇编语言为:

R2 = .2 M[R1+2];
R3 = R2 + 1;
M[R1] = .2 R3;

# for 循环是如何翻译的

int array[4];
int i;
for(i=0;i<4;i++){
    array[i] = 0;
}
i--;

首先是内存的申请,假设现在已经申请好了空间,那么执行 for 循环,第一步就是 i = 0

M[R1] = 0;

下面进行判断关系 i < 4。这里的 BGT 是分支指令 branch greater or equal 的缩写,意思就是如果第一个参数大于等于第二个参数就进行跳转到第三个参数的地址上,否则继续按顺序执行。

R2 = M[R1];
BGE  R2,4,PC+? 	//这里暂时不知道从基地址偏移多少个4字节(汇编指令的大小)
R3 = M[R1];		//R3就是i
R4 = R3 * 4;	//乘4因为int占4字节,R4是相较于数组基地址偏移后的地址
R5 = R1 + 4;	//R5是数组的基地址
R6 = R5 + R4	//R6是本轮循环要操作的数组元素的地址
M[R6] = 0;		//array[i] = 0;

接着进行 i ++

R2 = M[R1];
R2 = R2 + 1;
M[R1] = R2;

接着执行分支指令,跳回判断语句,这里是无条件跳转,即 JMP

JMP PC-40;

下面该写循环执行完,跳出循环后的 i – 了,并且现在我们可以把循环中的?给替换了,可以知道偏移应该是 10 条指令的大小,也就是 40。所以 ?=40

R2 = M[R1];
R2 = R2 - 1;
M[R1] = R2;

对于 32 位操作系统,汇编代码指令一共有 32 位,为了能够表示 59 中汇编指令,需要 6 位进行表示,就是前六位是操作码。硬件会在一个时钟周期的前一部分,查看前 6 位机器码是什么,然后再决定如何解释剩下的 26 位。当然,这是使用定长编码对汇编指令进行编码,也可以使用非定长的编码方式。

# 指针和强制类型转换

下面以一个结构体为例:

struct fraction{
	int num;
    int denom;
};
struct fraction pi;
pi.num = 22;
pi.denom = 7;

对于结构体,其内存如下图所示

image-20231118165258248

对于上述代码的汇编语言为:

M[R1] = 22;
M[R1+4] = 7;

如果再进行以下操作:

((struct fraction *)&pi.denom) -> denom = 451;

这句代码的意思就是:

image-20231118165751885

那么这里的汇编代码是什么样的?如下:

M[R1+8] = 451;

pi 的地址是 M [R1],pi.denom 的地址是 M [R1+4],对其进行强制类型转换不会改变它的地址,->denom 的地址是 M [R1+4+4]。