关于结构体中,位域成员的赋值原理:
struct PTE
{
int offset : 12;
int pgNo : 20;
}
struct PTE pte = {64,3};
给pte赋值,其实就是 (3<<12) | 64
原理:由于struct PTE占32位,3想赋值给第二个成员,而64想赋值给第一个成员,而64的高12位一定会为0的(这是程序员肯定会控制的)
在 C 语言中,&number 的类型是指针类型,但在汇编指令中,我们使用符号 number 即可表示一个地址常量,
int number;
int arr[4][5];
int * ptr1 = &number;
int * ptr2 = arr[2];
对应的汇编//
ptr1:.long number
ptr2:.long arr + 40
中间代码生成简介
在语法分析和语义检查阶段,我们始终在与语句 Statement、表达式 Expression 和外部
声明 ExternalDeclaration 这 3 个概念打交道。通过声明,我们最终建立起了相应的类型结构,
并在符号表中保存了相关标识符的类型信息,到了中间代码生成阶段,我们就不再需要处理
外部声明 ExternalDeclaration 了,只需要为语句和表达式生成相应的中间代码即可。文件
ucl\tranexpr.c 用于为表达式生成中间代码,文件名 tranexpr 是 Translate Expression 的缩写,
而 ucl\transtmt.c 则用于为语句生成中间代码。
由此,基本块成了点,而“控制流的转移”就成了有向边,我
们可把整个程序的动态执行的路线看成数据结构中的“图”,这个由基本块构成的图被称为
控制流图 Control Flow Graph,简写为 CFG。后续的分析和优化都是基于“控制流图”这样
的数据结构进行。需要说明的是,UCC 编译器的中间代码优化工作只在基本块中进行,并
没有进行函数间(过程间)的代码优化,因此 UCC 编译器在划分基本块时,并没有把函数
调用当作基本块的最后一条指令,其实是不太对的,因为基本块的意思是,内部从前往后执行,不会产生跳转,但是函数调用其实就是CPU发生了跳转的,只是又跳回来了而已。
c语言中的短路运算:
而对于布尔表达式来说,我们并不会
对整个表达式进行求值,而是生成相应的跳转指令,对于 a&&b 而言,当 a 为假时,不论 b
为何值,a&&b 的值都为假,所以此时我们并不需要对 b 进行求值。若把“a&&b”换成
“f()&&g()”,则当 f()的返回值为假时,我们不需要对函数 g()进行求值,此时 g()函数根本
就没有被调用,这就是 C 语言中的短路运算。