宏-内联函数, 内存对齐,

预处理(.i)-宏定义,条件编译指令,注释
编译(.s)
汇编(.o)-二进制文件,机器指令,与上一步统称为编译
链接(.exe)-将相关文件彼此链接

宏,简单的替换
内联函数(inline),节约一些小函数频繁调用,大量消耗栈空间的问题。
inline必须与函数的定义放在一起,才能是内联函数,编译时处理内联。
volatile,与const相对,volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,
比如:操作系统、硬件或者其它线程等。

遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。
声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。
在单任务的环境中,一个函数体内部,如果在两次读取变量的值之间的语句没有对变量的值进行修改,那么编译器就会设法对可执行代码进行优化。
由于访问寄存器的速度要快过RAM(从RAM中读取变量的值到寄存器),
以后只要变量的值没有改变,就一直从寄存器中读取变量的值,而不对RAM进行访问。

(1)并行设备的硬件寄存器(如:状态寄存器); 
(2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables); 
(3)多线程应用中被几个任务共享的变量。

在内存中的存储形式,数值以补码表示,字符以ASCII代码表示。
任何数据都是以二进制形式在内存中存放的。
关于指针变量的长度,指针不是一般变量,存的是变量的地址,在同一架构下地址长度都是相同的(CPU最大寻址内存空间),
所以不同类型的指针长度都是相同的。

内存对齐的3大规则:
1 对于结构体的各个成员,第一个成员的偏移量是0,排列在后面的成员其当前偏移量必须是当前成员类型的整数倍
2 结构体内所有数据成员各自内存对齐后,结构体本身还要进行一次内存对齐,保证整个结构体占用内存大小是结构体内最大数据成员的最小整数倍
3 如程序中有#pragma pack(n)预编译指令,则所有成员对齐以n字节为准(即偏移量是n的整数倍),不再考虑当前类型以及最大结构体内类型
数据成员放入内存的时候,内存拿出一个内存块来,数据成员们排队一个一个往里放,遇到太大的,不是把自己劈成两半,能放多少放多少,而是等下一个内存块过来。
struct mn
{   char a;
    int m;
    char b;}
sizeof(mn) = 1 + (3) + 4 + 1 + (3) = 12 (中间补,最后补)
union类型比较特殊,计算union成员的偏移量时,需要根据union内部最大成员类型来进行缓冲补齐
C++标准规定:一个空类的大小为1个字节

引用和指针:
引用必须被初始化且只能初始化为另一个变量,但是不分配存储空间
指针不声明时初始化,在初始化时分配存储空间
引用初始化以后不能改变,指针可以改变所指的对象
不存在指向空值的引用,但是存在指向空值的指针
重载-名称相同,但是参数列表数目或者类型不同
覆盖-名称相同,参数列表数目和类型相同,被覆盖的不能使static,必须是

virtual。
重定义-派生类对基类方法的重定义,函数名必须相同
多态-为了避免在父类里大量重载引起代码臃肿且难以维护
静态多态性-通过函数重载实现  动态多态性-通过虚函数实现

set和multiset
会根据特定的排序准则,自动将元素进行排序,不同的是后者允许元素重复而前者不允许,
#include<set>
通常以红黑树实现的,自动排序的优点是使得搜寻元素时具有良好的性能,具有对数时间复杂度。
但是造成的一个缺点就是:
不能直接改变元素值。因为这样会打乱原有的顺序。
改变元素值的方法是:先删除旧元素,再插入新元素。
存取元素只能通过迭代器,从迭代器的角度看,元素值是常数

猜你喜欢

转载自blog.csdn.net/shidamowang/article/details/79997970