2018-10-21

进程终止

exit(int) 执行若干清理活动之后调用 _Exit(int) 返回内核。等价于主函数 return 对应的退出码。使用 atexit(void (*)(void)) 注册函数,在退出之后调用。但至多指定 32 个函数。执行完这些用户指定的函数之后,再执行设定好的清理活动,典型的例子可能是 fflush(stdout) 这类事情。

C 程序进程的存储空间

  • 正文段(text):机器指令,一般是只读的。

  • 初始化了的数据段(数据段,data):在 C 的函数外声明初始化后的数据。例如 int maxc = 99; 这样的变量。

  • 没有初始化的数据段(block started by symbol,bss):C 函数外声明成 long sum[128]; 这等数据。会自动初始化为 0。

  • 栈(stack):自动变量储存的位置,包含函数调用信息。每个函数的调用得到一块栈帧,函数结束之后释放栈帧(实际上只是指标移动导致内存可以被重复利用而已)。

  • 堆(heap):用于动态内存分配。

下面是一个典型的内存分布模型(在程序的虚拟内存空间内):

| text | data | bss | heap -->     <-- stack | ... |

堆部分从低地址向高地址扩展;栈内存从高地址向低地址扩展。Unix 给出一个 size 程序,以可执行文件为参数,得到它的 bss 、data和 text 段的大小。

共享库

gcc 使用 -static 选项禁止链接动态库,转而全部链接动态库。得到的可执行程序 data 和 text 都会变得巨大无比。

共享库除了减少程序空间,还使得库版本更新(不改变接口的前提下)不必重新编译被依赖的程序。

setjmp

setjmp.h 中的 setjmp(jmp_buf)longjmp(jmp_buf, int) 可以实现栈直接跳转,具体细节参看文档。

习题

很多 Unix 系统中,有意禁止访问数据段(data)的 0 地址处,这是为什么?

C 语音禁止解引用 NULL 指针(因为这是没有意义的)。data 段的 0 禁止访问,则不必手动实现这种禁止。

你可能感兴趣的:(2018-10-21)