进程映像
程序就是存储在磁盘上的可执行文件,当程序运行时,系统会将可执行文件加载到内存中,从而在内存中形成进程(一个程序可以同时加载出多个进程)
进程在内存空间中的分布情况就是进程映像,从低地址到高地址依次分布为:
text 代码段(只读段) 二进制指令、常量(字符串字面值、const修饰过的
原data段的数据),修改会产生段错误
data 数据段 初始化过的全局变量和静态局部变量
bss 静态数据段 未初始化过的全局变量和静态局部变量
该段内存开始前会被清理为0
heap 堆 体量较大的数据,例如结构变量
手动管理、释放时间可控,足够大,需要与指针配合使用
使用麻烦,可能会产生内存碎片和内存泄漏
stack 栈 局部、块变量
自动分配、释放内存,不会产生内存碎片、内存泄漏
大小很有限,释放时间不可控
environ 环境变量表 环境变量
每个进程都有一份,修改不会影响其他进程
argv 命令行参数 程序执行时附加的参数
变量的分类:
存储位置、生命周期、作用范围:
全局变量:定义在函数外
data或者bss
从程序运行开始到程序结束
任何位置都能使用
局部变量:定义函数内
stack
从定义的位置开始到函数结束
只能在函数内使用
块变量:定义在if\for\while等语句块
stack
从定义的位置开始到函数结束
只能在语句块内使用
注意:全局变量、局部变量、块变量是可以同名的,局部变量会屏蔽全局变量,块变量会屏蔽全局变量、局部变量
建议全局变量首字母大写
类型限定符
auto 用于定义自动申请、释放内存的变量,不加就代表加
不能在全局变量前使用,不能与static同时使用
extern 声明外部的全局变量
当a.c中定义一个全局变量,b.c中如果想要使用该全局变量,则需要用extern声明一下
extern 声明只能暂时瞒过编译阶段,如果链接时找不到该变量的定义语句,依然还是会报错的
static
限制作用域
改变全局变量、函数
改变存储位置
局部变量、块变量,由stack改为data或者bss
延长生命周期
局部变量、块变量,不会被自动销毁,它们的初始化语句只能是第一次使用时有效
void func(void)
{
static int num = 0;
}
const 用于"保护"变量不被显示地修改
初始化过的全局变量和静态局部变量被const修饰后,存储位置从data改成了text,就成为了常量,再强制修改会产生段错误
volatile
如果变量没有显示地修改,再使用变量时会继续使用上一次从内存中读取到的结果,
而不会重新读取(编译器的取值优化)
有些变量可能会被隐式地修改,要想随时正确地获取到该变量的值,则需要用volatile来修饰
在硬件编程、多线程编程中使用
register
申请把变量的存储位置从内存改为寄存器,这样能够提高变量的读写速度,从而提高程序运行的速度
由于寄存器稀少,申请不一定能成功
注意:这种变量不能取地址 &
typedef
类型重定义,当定义变量时,使用typedef,变量名就变成了这种类型
typedef int num; num == int
常用的size_t time_t uint8_t 都是类型重定义
注意:不是替换