核心简记
- c++可以直接用的算数类型:bool(可赋予true或非0|false或0)表示出来为1或0;char(规定8位,GBK用俩个char表示);wchar-t宽字符;char16-t;char32-t用于unicode;short;int;long;long long;float;double;long double
- unsigned可用于char、int、short、long与long long;signed用于char。因为char的实现无符号还是有符号没定
- 类型转化:bool对外表示为0或1,可接受任意数字与truefalse,0为false。浮点赋予整形舍弃小数位。有符号与无符号表达式会转为无符号,负数的无符号会按补码计算无符号。不要使用和过度关注依赖编译环境的问题
- 字面值:0开头8进制,0x开头16进制。10进制字面值是带符号数,可用前后缀指定最小匹配。浮点默认double类型指数可用e标识。true与false是字面值。nullptr是指针字面值
- 俩个字符串字面值仅由空格换行分割时当成一个整体,可用转义符与泛化转义
- 字面值前缀字符与字串用:u(unicode16位)U(unicode32位)L(宽字符)u8(UTF-8仅用于字符串)。后缀整形:u/U(unsigned)l/L(long)ll/LL(long long)。后缀浮点型:f/F(float)l/L(long double)
- c++中,初始化与赋值是俩个完全不同的操作。{}列表初始化对转化要求更为严格。内置类型都应该初始化,类的初始化由类定义
- 为了支持分离式编译,c++将声明与定义区分开:声明使得名字所知,用于使用名字与类型。定义负责创建与名字关联的实体,用于分配空间与初始化。extern用于声明,如果初始化就成了定义。定义只有一次但可多次声明使用。
- C++为静态类型语言,即编译阶段检查类型,该检查判断出数据类型是否支持要执行的运算。适合复杂程序
- 定义应该放在使用附近,全局作用域下的名字使用::(前为空)访问。内可访问外层,内定义覆盖外层。
- 复合类型:基于其它类型定义的类型。见引用与指针
- 声明:基本数据类型 声明符(含名字与类型相关修饰)。int *p:int是基本类型,*是类型修饰符,类型修饰符是声明符的一部分。注意只有数据类型是作用于全语句的,类型修饰符只管p。因此一句可以定义不同类型变量。
- 处理类型可用auto与decltype。类型别名等-见下
- 基本数据类型:基本内置类型与自定义类型。基本内置类型:算数类型与空类型。算数类型:整形(字符与布尔在内)与浮点型
- 动态类型语言:在运行期间检查数据类型python、ruby、js等。静态类型语言:运行前编译时检查类型java、c++、c#等
- 默认初始化:内置类型函数外的为0,内部的不初始化。类决定对象的初始化方式
引用
引用是为对象起了另一个名字。初始化后永久绑定,不可更改。引用并非对象,只是另一个名字。
d定义时必须初始化,类型除特殊外要求严格匹配。不可绑定字面值。
可以有指针的引用:
离变量名最近的符号&对变量类型最直接的影响,因此d是引用,其余部分确定引用的类型。注意从右向左阅读修饰。
指针
指针本身是一个对象,允许赋值与拷贝,无需定义时赋值。
引用不是对象,没有实际地址,不能定义指向引用的指针。除了特殊情况指针类型要求严格匹配。解指针引用得出所指对象。组成复合类型的符号与解引用符含义不同。
空指针初始可用nullptr,0。可以但不推荐NULL。应该初始化所有指针。暂不知道的就nullptr。
void*指针:特殊类型指针,可以存放任意类型对象的地址。
声明符中的修饰符没有个数限制,按逻辑关系解释即可,同时该声明明确了指针的具体类型。int **p;p是指向int的指针类型的指针。
const常量
|
|
- const关键字定义的对象必须初始化。之后不可被改变。
- 默认下,const只在文件内有效-编译单元,编译器将在编译过程中把用到const变量的都替换为对应值-但要分配空间的。想共享模块的const需要定义与声明都添加extern关键字
- 对常量的引用可以初始化为const、普通对象、任意能转化为引用类型的表达式。该const只是指明了该引用不可以使被引用的对象修改。也就是说该const是针对引用的可参与操作,引用本身就是不可被修改的
- 对于类型不一致可以的原因,是因为先用double初始化了一个const int &临时量,再用引用绑定这个临时量。也就是说const实际针对的是引用的类型
指向const的指针
|
|
想存放常量对象的地址,只能用指向常量的指针,但常量指针也可以存放普通对象的地址。常量指针仅要求不能通过该指针改变对象的值,也就是说规定的是该指针指向的类型是const。
const指针
|
|
同样右到左阅读,常量->指针->指向类型为int。该意思是指针本身为常量。指向类型的操作看指向类型的。
顶层const表示指针本身是个常量,底层const表示指针所指对象是常量。一般化,底层表示复合类型的,顶层表示本身。注意顶层底层是形容const的。
拷贝操作时,顶层不受影响。拷贝对象必须具有相同的底层const资格,或者俩个对象的数据类型可以转化。
常量表达式
|
|
常量表达式是指在编译时可以确定值的表达式,需要类型与初始值决定,字面值是。用常量exp初始化的const是。constexpr关键字由编译器验证变量的值是否是常量表达式,声明为该类型的变量一定是一个常量,而且必须用常量表达式初始化。当指针使用constexper时仅对指针有效-顶层且constexpr的指针和引用初始值限定很大。
处理类型
声明:基本数据类型 声明符(含名字与类型相关修饰)
类型别名
|
|
typedef作为基本数据类型的一部分,声明符的名字作为类型别名。与声明一样,其它部分组成类型。使用using也可以
将别名用于常量类型不太一样:
不是替换后的指向常量的意义,也就是说理解不能展开,而是当成一个整体。从右到左读:基本类型为指针,之后的const是修饰该指针的。
auto
|
|
编译器通过初始值(必须有)判断变量的类型。auto作为声明语句中的基本数据类型,多条声明符时基本类型是一致的。
引用给auto实际上是使用引用的对象。auto会忽略顶层const,底层const会保留
decltype
用于希望从表达式的类型推断出要定义变量的类型,但不用该表达式的值初始化变量。
编译器推断出exp的类型,并返回类型。该处理会返回真实的类型(包含const与引用)。一些表达式会向decltype返回引用类型,表示表达式结果对象可以做赋值语句的左值。
自定义数据结构
|
|
可以直接用类名定义对象。c式也允许但不推荐,此外类的定义后可以加定义的对象,但不推荐。类内成员可以初始值,推荐。
按模块编程的话,一组.h与.cpp文件应该共同实现一个类,类名与俩文件名应该相同。.h是作为被共享出去的接口部分,因此类的定义、const应该定义在.h中。
保护符名:大写类名+_H
预处理变量无视作用域,但是只在模块编译单元内生效。
反汇编
Android.mk
代码:
X86-64
指令简记
mov转义的大小看操作数和dword等类型
分析
|
|
注意:
- 补码的意义是0减这个数的绝对值,x+x(反)+1=0.所以推得常用补码计算式,其表达的意义是为了计算方便。以0为对称符合负数的自然表达(用了00x作为对称),将二进制串用高位一分为二(越过中间将错误),因此使二进制计算结果正确。
- 浮点数有其专用的指令与寄存器进行计算。浮点数表示方式为先将10进制实数化为二进制实数(这一步造成了精度损失)再将二进制实数表示为IEEE规定的科学计数法样式-符号、指数、尾数。
- 布尔型由编译器存为1或0。占一个字节。
- 地址只能取一次(&),指针的类型只有编译器知道,汇编层面都是相同大小(8字节地址线长度)存地址。只能看操作区分用途
- 引用实质就是指针…只是编译器封装了指针操作而已..汇编层面的指针与引用完全没区别。引用是占内存的。都是间接寻址。
- 字面常量存储于机器码与数据段中,由系统保护机制防改。const是分配内存的,只是编译期间放改,用指针是可以改的,但是即使分配了内存,编译器依旧是对其在编译时进行了常量替换。
- 分析:地址->权限->属性->内存布局->数据操作
ARM64-v8
指令简记
WZR:32位0寄存器
XZR:64位0寄存器
SIMD全称Single Instruction Multiple Data,单指令多数据流,能够复制多个操作数,并把它们打包在大型寄存器的一组指令集。
Neon是适用于ARM Cortex-A系列处理器的一种128位SIMD(Single Instruction, Multiple Data,单指令、多数据)扩展结构。
64位下NEON寄存器:
包括:
32个B寄存器(B0~B31),8bit
32个H寄存器(H0~H31),半字 16bit
32个S寄存器(S0~S31) ,单字 32bit
32个D寄存器(D0~D31),双字 64bit
32个Q寄存器(V0~V31),四字 128bit
FCVTZS:浮点转换为有符号定点,向零舍入。
分析
|
|
可见ARM的寄存器真的多….用的非常任性,先把值都放在寄存器再去赋予。c++的语法表示与x86基本相同..不过现代cpu针对计算有好多优化操作。