核心简记
- 表达式语句的作用是执行表达式并丢弃求值结果。语法定义的bnf为:块-语句-表达式
- 复合语句(块)也是语句,单独作用域,外不访问内,内可访问外。
- if、switch、while、for的控制结构内可以定义变量。作用域为相应语句内部。
- else if其实就是else下的语句为if语句。语法bnf定义的只有if与if else 。else匹配的是最近尚未匹配的if,块中的不会匹配
- switch也属于条件语句,每句应加break与{}
- c++规定不允许跨过变量的初始化语句直接跳转到该变量作用域内的另一个位置。
- 定义在while条件部分或者循环体内的变量每次迭代都会创建到销毁,之前试的那个基本类型初始化就是赋值所以不明显。类对象在栈中的话会调用构造与析构函数。分配栈中的空间会函数一开始就留好,每次初始化析构就可以了,但是堆中的是由运行时分配的,不会自动执行回收销毁,只是指针会创建销毁,因此堆中要手动释放。
- 范围for就是使用迭代器
- do while的最后有分号,条件使用的变量必须定义于循环体之外。
- break只作用于:负责终止离它最近的while、do while、for、switch。只是这些
- continue只作用于:for、while、do while
- goto只能同一函数内
- try与catch的语法、汇编实现见下-重点
范围for等价的是:
try-catch
异常处理使不同功能的代码分离。c++异常处理包括:
throw:异常检测部分使用,表示遇到异常
try:异常处理部分使用try-catch处理异常
异常类:传递信息
throw
|
|
throw+表达式,表达式的类型就是抛出的异常类型,必须加分号。
抛出异常终止当前函数,并把控制权转移给能处理该异常的代码。
try
|
|
try中发生异常中断执行,选中catch执行,之后跳转到最后一个catch子句之后那条语句。
try块与catch块独立作用域。
寻找处理代码过程:搜索抛出异常的函数catch,没找到就终止函数。并向外继续寻找。最终没有匹配将转到terminate标准库函数。
异常处理应该清理未完成工作。
标准异常
每个标准库异常都定义了what成员函数。
标准异常类 | 描述 | 头文件 |
---|---|---|
exception | 最通用的异常类,只报告异常的发生而不提供任何额外的信息 | exception |
runtime_error | 只有在运行时才能检测出的错误 | stdexcept |
rang_error | 运行时错误:产生了超出有意义值域范围的结果 | stdexcept |
overflow_error | 运行时错误:计算上溢 | stdexcept |
underflow_error | 运行时错误:计算下溢 | stdexcept |
logic_error | 程序逻辑错误 | stdexcept |
domain_error | 逻辑错误:参数对应的结果值不存在 | stdexcept |
invalid_argument | 逻辑错误:无效参数 | stdexcept |
length_error | 逻辑错误:试图创建一个超出该类型最大长度的对象 | stdexcept |
out_of_range | 逻辑错误:使用一个超出有效范围的值 | stdexcept |
bad_alloc | 内存动态分配错误 | new |
bad_cast | dynamic_cast类型转换出错 | type_info |
只能默认初始化exception、bad_alloc、bad_cast。其它用string或c风格字串初始化。
反汇编
RISC就是通过优化,选取最常用的指令,剔除了那些不太常用,却会大大增加运算器复杂程度的指令,使得运算器大幅度简化,这样就可以给每个寄存器配备一个独立的运算器。因此叫精简指令集
Application:
5.cpp:
X86-64
指令简记
传参是di、si–更多见函数章节
endp是过程结束
分析
|
|
|
|
if语句汇编效果为:不满足就跳过
if else语句的汇编效果为:在if块后多加个jmp跳出
else if汇编:
可见多重条件分支就是else内嵌套。从编译时语法处理看,BNF表示就俩种if语句:条件 true语句 | 条件 true语句 false语句
语句可以又是if语句,因此按bnf解析else if将被解析为else的语句是if语句,if语句可以含或不含else,因此最后加不加else都可以。默认先移进,因此else匹配最近的if。
构造AST后生成的代码依旧按左到右对应语句的顺序,因此生成的汇编代码如上。分支的基本单位是语句块,只要确定语句块的出入口就可以确定分支。此后就是高中的流程图分析了
关于switch的汇编:
不同于if,所有的case语句块是连在一起的,为了实现语法要求不加break可以继续执行。因此前面依次判断条件跳转。根据条件数字结构不同,可以有:
- case数量小时,直接依次cmp判断,此时效率不如if
- 线性且连续时,case地址放于数组中,用下标间接跳转。
- 线性且差不太大时,俩个表,地址表存case地址,索引表存地址表下标,内容小、因此索引表可以大点。间接俩次
- 差值大时,采用平衡二叉树,采用编译好的连续cmp+跳转实现
优化时,当子树的叶子节点不大于3时,会编译为ifelse结构而不平衡。当子树可以有1、2、3、4中优化措施时,将对子树采用以上的编译方式。因此判断分发部分常常是混合使用的,case部分是连续的始终。
函数的块内作用域都是编译器负责检查的,统一分配在栈中实际
do-while:
while:
for:实际上ndk编译for的结果与while一样,把计算步长放到jmp B前了
计算效率dowhile>while>=for。
异常处理部分暂时看不懂….收集了一些资料,在18章中深入进行分析….
一篇不错的文章:
https://monoinfinito.wordpress.com/series/exception-handling-in-c/
window下c++的异常机制-比较专业的文档:
http://www.ecice06.com/CN/article/downloadArticleFile.do?attachType=PDF&id=10631
ARM64
指令简记
分析
|
|
|
|