核心简记
- 内置类型的运算符操作由语言定义
- 重载运算符的操作对象类型与返回值类型可以自己定义,但是运算对象的个数、优先级、结合律无法改变
- 表达式的求值结果分为左值与右值,记住左身份右内容就可以了
- 优先级与结合律只是规定了当前表达式对象的求值顺序。但是运算对象的求值顺序是没有指定的。比如(i++)*(i–)的结果是不定义的,因为*的左右对象求值顺序并不指定,只要求在*之前求出俩运算对象的值即可。规定求值顺序的有:&&||?: 从编译过程来看的话就是左右子树的求值顺序不定,但保证在该节点求值时子树节点处理完,翻译时为直线翻译但顺序不定,此外给予优化以方便。从一个表达式整体来看,其用到的对象只要保证表达式求值时前求好值即可,顺序都不定。优先级和结合性是编译时概念,与求值顺序独立,后者是运行时概念。
- 数学规定(m/n)*n+m%n=m因此m/n符号不同为负,m%n符号与m相同。且整数商一律向0取整。
- 逻辑运算规定先求左侧的值再求右侧的值,为短路求值。具体实现为翻译时采用用条件跳转优化。
- 测试非布尔值的布尔就直接写在条件里,否则非布尔值会使布尔向上提升。
- 列表初始化或列表赋值的要求:使用参数为std::initializer_list的构造函数或赋值运算符,或者是这个类满足 aggregate class 的条件。对于类来说,赋值运算的细节由定义定。
- ++–前置与后置:前置为先改变对象再返回改变后的对象,后置为改变对象再返回改变前的值的副本。与赋值操作使用要小心,因为赋值左右的求值顺序不定。
- 变量是一个具名的、可操作的存储空间,有其数据类型。数据类型决定变量的空间及操作。点运算符针对变量,箭头针对指针变量。变量在编译原理下就是分配的一块地址中的内容。*是取这个内容作为地址再将地址所在内容作为对象。.是寻找该内容中的某对象或操作。这些语法大多是给编译器认识的,具体到汇编层面只有地址:值,寄存器。针对这些地址、值做操作。
- 条件运算符的俩个表达式只会求值一个。
- 位运算符没有规定符号位,因此不用于有符号类型。且小整形会被提升。
- sizeof有俩种:sizeof (type)求类型的对象所占大小与 sizeof exp求表达式结果类型的大小,表达式并不求值。对引用为被引用的对象所占大小,指针为指针本身大小,解指针为指针指向对象所占大小,对数组为整个数组所占大小(数组这里含义特殊,不当指针了),string与vector只返回固定部分的大小。返回结果为size_t类型的常量表达式-编译时确定。
- 算数类型之间的隐式转化被设计的尽可能少损失精度,发生于:表达式类型统一,条件中化为布尔,赋值中左变右,小整数会被提升为int,有符号与无符号混合化为无符号
- 大多数数组的表达式中,数组自动转化为指向数组首元素的指针。例外是:decltype、取地址(所以&a返回的不是指针地址而是数组地址)、sizeof、typeid。
- 类类型的转化由类类型自己定义,从类转化出去或是别的转化过来都可以定义。
- 显示转化见下
- 优先级表见下
显示转化
显示转化采用cast-name
- static_cast:具有明确定义的类型转化,不包含底层const
- dynamic_cast:运行时类型识别
- reinterpret_cast:底层重新解释,如指针化为int
- const_cast:用于改变运算对象的底层const
旧式转化(type) exp;根据type类型不同,旧式可化为其中之一,
c++运算符优先级表
https://zh.cppreference.com/w/cpp/language/operator_precedence
插入图
反汇编
源码:
x86-64
指令简记
cdq:把EAX的符号位复制到EDX的每一个 bit 上
DIV SRC:
字节操作:16位被除数在AX,8位除数为源操作数,结果的8位商在AL中,8位余数在AH中。表示为
(AL)<-(AX)/(SRC) 的商
(AH) <-(AX)/(SRC) 的余数
字操作:32位被除数放在DX,AX中。其中DX为高位字,16位除数为源操作数,结果的16位端在AX中,16位余数在DX中。表示为
(AX)<-(DX,AX)/(SRC) 的商
(DX)<-(DX,AX)/(SRC) 的余数
双字操作:64位被除数在EDX,EAX中,其中EDX为高位双字,32位除数为源操作数,结果的32位商在EAX中,32位余数在EDX中,表示为
(EAX)<-(EDX,EAX)/(SRC) 的商
(EDX)<-(EDX,EAX)/(SRC) 的余数。
DIV均为无符号数,IDIV为符号数
IMUL r/m ;单操作数
如果参数是 r8/m8, 将把 AL 做乘数, 结果放在 AX
如果参数是 r16/m16, 将把 AX 做乘数, 结果放在 EAX
如果参数是 r32/m32, 将把 EAX 做乘数, 结果放在 EDX:EAX
IMUL r16/r32, r16/r32/m16/m32/i ;双操作数, (1)(2) -> (1)
IMUL r16/r32, r16/r32/m16/m32, i ;三操作数, (2)(3) -> (1)
同样I为有符号
分析
|
|
sizeof是直接编译时计算的,因此编译为常数,其它都是正常汇编指令使用。注意release模式下的除法与乘法会有很大优化改动。
值得一提的是ida反编译也进行了优化…把不影响外界、输入出等的汇编代码不进行反编译。
ARM64
指令简记
UXTB:字节被无符号扩展到32 位(高24 位清0——译注)
MADD W10, W10, W8, WZR
W10=W10*W8
分析
|
|