传送门《高质量C编程教程汇总》
1.数据类型的意义
(1)定义了数据占用的内存空间大小
(2)定义了数据的取值范围
(3)定义了数据在内存中的存储格式
(4)决定了数据的运算规则
(5)为编译器提供了检查依据
2.数据类型作用时机:编译时
编译完成的结果—机器码,仅仅是CPU运行的指令集,此时不作任何判断,就是执行而已
编译需要知道某个值是属于哪种数据类型,以便正确解释数据
3.多字节数据在内存中的存放
int a = 0x12345678
(1)Intel CPU小端存放数据(主流)
高地址 | 12 | 34 | 56 | 78 | 低地址 |
---|---|---|---|---|---|
内存中形式(低) | 78 | 56 | 34 | 12 | (高) |
(2)大端存放数据(摩托罗拉CPU)
(3)ARM默认小端,也可以调至大端
注:char a[4]
没有大小端的问题
4.结构体变量所占内存空间大小
(1)基础知识:32位CPU因为字长为32位,读内存数据时,一次会读取4个字节的内容,且读取的4个字节数据首地址是能被4整除的(0,4,8,C)
(2)为了加快CPU存取速度,C编译器在处理数据时,把结构体变量成员的摆放按照某个对齐原则规划,叫做边界对齐
(3)以牺牲空间来换取效率
5.边界对齐的3个准则
(1)首地址:
结构体变量的首地址能够被其最宽基本类型成员大小与4的较小者所整除
(2)每个成员放法:
结构体每个成员相对于结构体首地址的偏移量(offset)都是该成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在成员之间加上填充字节(默认对齐基数是8)
(3)结构体总大小:
结构体总大小为结构体最宽基本类型成员大小与对齐基数中的较小者的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(补齐原则)
6.”对齐”规则的补充
(1)在寻找最宽基本类型成员时,应当包括复合类型成员A的子成员,而不是把复合成员A看成是一个整体
(2)但在确定复合类型成员A的偏移量时则是将复合类型作为整体看待(规则二:偏移量offset都是该复合类型成员A的最大成员大小与对齐基数中的较小者的整数倍)
7.合理编排结构体成员:
由小到大
8.工程中,这样使用结构体,让程序可读性更强
struct B struct B
{ {
char c1; char c1;
char c2; char c2;
---> char padding[2];
int a; int a;
float f; float f;
}; };
9.其他修饰变量的关键字
(1)volatile - 避免编译器优化
(2)const - 可以保护被修饰的东西,防止意外的修改(当编程开始习惯使用const时,程序将上升一个档次)
int const i = 10; <=> const int i = 10;
int *const p = &i; //常指针,指针永远指向同一内存地址
const int *p = &i; //指向常量的指针,不能通过指针p来改变;
(3)register -
register int i= 10;
寄存器变量 - 可以被存储在CPU寄存器中,这仅仅是个请求,未必成功
①可以使用register声明的类型有限,例如32位寄存器不够容纳double型
②寄存器数量有限,不够时变量申请放到寄存器中也未必成功
(4)static - 静态变量(作用域为当前C文件中)
(5)extern - 全局变量(作用域为全程序),只是声明,没有开辟存储空间
10.C语言中的零只有3种
(1)数值0
(2)字符串结束标识\0
(3)指针NULL #define NULL (void*)0