unix环境高级编程-进程环境
main函数:
int main(int argc, char *argv[]);
当内核执行一个c程序时(使用一个exec函数),在调用main前先调用一个特殊的启动例程,可执行文件按将此例程作为程序的开始地址-这是由连接编辑器设置的,而连接编辑器由c编译器调用,启动例程从内核取得命令行参数和环境变量,然后按上述方式调用main函数。
进程终止的几种方式:
1. 从main返回
2.调用exit
3.调用_exit
4.最后一个线程从其启动例程返回
5.从最后一个线程调用pthread_exit
异常终止有三种方式:
1.调用abort
2.接到一个信号
3.最后一个线程对取消请求做出响应
退出函数:
三个函数用于正常终止一个程序:_exit和_Exit立即进入内核,exit先执行一些清理程序,然后返回内核。
三个退出函数都带有一个整型参数,称为终止状态(或退出状态)。如果调用这些函数不带终止状态或者main函数执行了一个无返回值的return语句,或者main没有声明返回类型为整型,则该进程的终止状态是未定义的。但如果main的返回类型是整型,兵器main执行到最后一条语句返回,那么该进程的终止状态是0。
main函数返回一个整型值与用该值调用exit是等价的。也就是说exit(0)等价于return(0)。
函数atexit
一个进程可以登记多至32个函数,这些函数由exit自动调用,称这些函数为终止处理程序,调用atexit函数来登记这些函数。exit调用这些函数的顺序与它们等级时候的顺序相反。
上图显示了一个c程序是如何启动,以及它终止的各种方式,上图可以看出,内核使程序执行的唯一方法就是调用一个exec函数。进程自愿终止的唯一方法是显式或隐性调用_exit或_Exit。在结束程序时,exit首先调用各终止处理程序,然后关闭所有打开流。
命令行参数:
当执行一个程序时,调用exec进程可以将命令行参数传递给新程序。由于argv[argc]是一个空指针,可以将参数处理循环改写
for(i=0; argv[i]!=NULL; i++)
c程序的存储空间布局
正文段:由cpu执行的机器指令部分
初始化数据段。它包含了程序中需明确赋初值的变量。比如int maxcount-=99;
未初始化数据段:bss段,内核将此段的数据初始化为0或空指针 long sum[100];
栈:自动函数以及每次函数调用所需保存的信息都存放在此段中,
堆:在堆中进行动态储存分配
共享库:
使得可执行文件中不再需要包含公用的库函数,程序在使用库函数时,用动态链接的方法将程序与共享库函数相链接,减少了可执行文件的长度。但增加了运行时间的开销。
gcc -static:gcc的static参数阻止gcc编译使用共享库,这样编译出的程序比较大
存储空间分配:
malloc 分配指定字节数的存储区。
calloc,为指定数量指定长度的对象分配存储空间
realloc:增加或减少以前分配区的长度。
void* 表示未确定类型的指针。C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针。
函数free释放ptr指向的存储空间。
大多数实现所分配的空间比所要求的要稍大一些,额外的空间用来记录管理信息-分配的长度,指向下一个分配快的指针等,这意味着,如果超过一个已分配区的尾端或者在起始位置前进行写操作,则会更改另一块的管理记录信息。这种错误是灾难性的。
还有一些致命的错误:比如调用了malloc却忘记调用free,该进程占用的存储空间会联系增加,被称为泄漏,若不调用free释放,进程地址空间长度会慢慢增加。直到不在有空闲空间。
环境变量:
#include <stdlib.h>
char *getenv (const char *name); 此函数返回一个指针,它指向name=value,中的value。
除了获取环境变量值,有时也需要设置环境变量。下表列出了不同的标准及实现支持的各种函数。
此函数返回一个指针,它指向name=value字符串中的value。
这些函数在修改环境表的操作是怎么样的?
删除一个字符串很简单,在环境表中找到该指针,然后将所有后续指针都向环境表首部移动一个位置。但增加和修改就很难。环境表通常占用的是进程地址空间的顶部,不能再往上拓展,同时也没法在它之外的各栈桢。
修改一个现有的环境变量:如果新value长度少于等于现有value差高度,只需要将新字符串复制到原字符串所用的空间中;如果新value的长度大于原长度,则必须调用malloc为新字符串分配空间,然后将新字符串复制到该空间中,接着改变指针指向。
如果要增加一个新的name:先带哦用malloc为name=value分配空间然后将该字符串复制到此空间中。
函数setjmp和longjmp
在c中,goto语句是不能跨越函数的,而执行这类跳转功能的是函数setjmp和longjmp。对于处理发生在很深层嵌套函数调用中的出错情况是很有用的。
但是要注意的是,当调用longjmp回到执行main函数时,变量和寄存器变量的值会变吗。答案是看情况,所有标准称它们的值是不确定的。因此如果你有一个自动变量,而又不想让其值回滚,可定义具有vloatile属性,
posted on 2016-07-28 19:48 sichenzhao 阅读(153) 评论(0) 编辑 收藏 举报