C语言细枝末节
数据相关
16位操作系统:long:4字节,int:2字节
32位操作系统:long:4字节,int:4字节
64位操作系统:long:8字节,int:4字节
所以最好使用 stdint 内的指定位数的定义(如int8、int32等)保证移植的兼容性
声明
- 用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化(告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据)
static
全局(静态)存储区:分为 DATA 段和 BSS 段。DATA 段(全局初始化区)存放初始化的全局变量和静态变量;BSS 段(全局未初始化区)存放未初始化的全局变量和静态变量。程序运行结束时自动释放。其中BBS段在程序执行之前会被系统自动清0,所以未初始化的全局变量和静态变量在程序执行之前已经为0。存储在静态数据区的变量会在程序刚开始运行时就完成初始化,也是唯一的一次初始化。
- 在修饰变量的时候,static 修饰的静态局部变量只执行初始化一次,而且延长了局部变量的生命周期,直到程序运行结束以后才释放。
- static 修饰全局变量的时候,这个全局变量只能在本文件中访问,不能在其它文件中访问,即便是 extern 外部声明也不可以。
- static 修饰一个函数,则这个函数的只能在本文件中调用,不能被其他文件调用。static 修饰的变量存放在全局数据区的静态变量区,包括全局静态变量和局部静态变量,都在全局数据区分配内存。初始化的时候自动初始化为 0。
- 不想被释放的时候,可以使用static修饰。比如修饰函数中存放在栈空间的数组。如果不想让这个数组在函数调用结束释放可以使用 static 修饰。
- 考虑到数据安全性(当程序想要使用全局变量的时候应该先考虑使用 static)。
内存
栈(stack)
核心特性
- 自动分配与释放:由编译器自动管理,函数调用时分配栈帧,函数返回时自动释放。
- 后进先出(LIFO)
- 高速访问
- 空间有限
存储内容
- 局部变量:函数内部定义的变量。
- 返回地址:函数执行完毕后返回的位置。
- 函数参数:调用函数时传递的参数。
- 寄存器值:保存调用前的寄存器状态,以便恢复。
优缺点
- 优点:无需手动管理内存,速度快,不会内存泄漏。
- 缺点:生命周期固定(函数结束即释放),空间有限。
堆(heap)
核心特性
- 手动分配与释放:使用malloc/calloc/realloc分配,free释放。
- 动态生命周期:内存块的生命周期由程序员控制,可跨函数使用。
- 碎片化问题:频繁分配和释放可能导致内存碎片,降低空间利用率。
- 慢速访问:需通过指针间接访问,效率低于栈。
存储内容
- 动态分配的对象:如malloc返回的内存块。
- 大型数据结构:如数组、链表、树等需要动态调整大小的结构。
- 跨函数数据:需要在函数调用结束后继续存在的数据。
指针
空指针:指针变量指向内存中编号为0的空间
野指针:指针变量指向非法的内存空间
1 | //指针指向的值是不可以更改的 |
数据集合
共用体(union)
所有成员共用一块内存,大小取决于最大大小成员
枚举(enum)
默认从 0 开始递增
位域(Bit Field)
位域用于结构体中,定义每个字段占用的比特位数;越前面定义的在内存的越高位
1 | struct Flags { |
注意事项:
- 位域不能取地址(&f.ready 不合法)
- 字段数值不能超过位数范围(2^n - 1)
- 与具体编译器实现密切相关(跨平台需小心)
位运算
1 |
|
编译和调试
四阶段
1 | gcc -E main.c -o main.i # 预处理 |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 Xiao's Blog!