标签:
标签(空格分隔): linux
以下内容来自《UNIX环境高级编程》读书笔记
首先想想下面几个问题能不能解答:
进程是程序执行的基本,进程即为程序执行的活动体。下面是进程在系统上运行的一些环境。
int main(int argc, char *argv[]);
当执行c程序的时候,在调用main函数之前会调用一个特殊的启动例程。可执行程序文件将次启动例程(Start Routin)指定为程序的起始地址(这是有链接的过程设置的)。启动例程会去内核中取命令行参数和环境变量值,然后对调用main函数之前进行一些环境的初始化。
对启动例程感兴趣的可以参考下面的链接看下:
how does linux execute my main()?
main函数和启动例程
书上说的是有8种情况下进程终止:
5中正常终止:
3种异常终止:
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
前面两种属于ISO C的,后面一种属于POSIX
_Exit = _exit 作用相同
exit与_exit的差别在于,_exit会直接返回内核,而exit会先进行一些清理操作。
C代码的启动例程可以是这样的:
exit(main(int argc, char* argv[]))
书上说因为什么历史原因,导致exit函数总是执行一个标准IO库的清理操作:即对所有打开的流调用fclose函数,这就造成输出缓冲的数据都被冲洗(刷新:写到文件中)
三个函数都有一个status参数值,这是进程终止的状态值。
还记得原来刚学习的时候有main函数如下写法:
void main(void)
就相当于最后结束的时候只是return,没有返回值,给exit的status就是空的。
return(0) = exit(0)
有一点指明的是,当main函数没有返回值,那么他的返回值是随机的,未定义的。
main函数声明为返回int的,这是POSIX和ISO定义。
进程登记函数,ISO的规定一个进程可以登记最多32个函数,这些函数有exit自动调用,这些函数为终止处理函数.
#include <stdlib.h>
int atexit(void (*func)(void));
//若成功,返回0;若出错,返回非0
参数是一个函数地址。
exit调用这些函数的顺序与登记顺序相反(估计登记的时候是放在栈中的。)同一个函数若登记多次,也会调用多次。
前面所说的这些都可以用下面这张图来解释清楚:c程序启动和终止
注意,内核使程序执行的唯一方法是调用一个exec函数来调用程序。进程自愿终止的唯一方法是显式的或者隐式的(通过调用exit)调用_exit或者_Exit。进程也可以非自愿的有一个信号使其终结。
调用exec执行一个程序的进程可以将命令行参数传递给该新程序。
参数存储在一张参数表中,类似于环境表,如下。
每个程序接受一张环境表,环境表是一个字符指针数组,只是存储环境变量的字符串的首指针。全局变量environ包含该指针数组的地址:
extren char **environ;
环境表的结构如下:
环境变量在linux等系统属于必须知道的东西。
环境变量字符串形式是key-value形式的。linux的环境变量设置和查看的底层函数:
#include <stdlib.h>
char *getenv(const char *name)
//成功,返回name关联的value指针;没有找到的,返回NULL
int putenv(char *str)
//成功返回0 失败返回非0
int setenv(const char *name, const char *value, int rewrite)
int unsetenv(const char *name)
简单的说下这几个函数:
这是一种经典的存储模型。
图中显示的是这些段的一种经典的安排。
栈顶和堆顶之间的未用的虚拟空间很大。
a.out中还包含了若干其他类型的段,如包含符号表的段,包含调试信息的段,以及动态共享库链接表的段等(《程序员的自我修养》中讲的很清楚)。但是这些部分并不会装载到进程执行的程序映像中的。
图中看出:
共享库使得可执行文件中不再需要包含公用的库函数,而只需在所有进程都可引用的存储区中保存这种库例程的一个副本。这样可以大大的减少每个执行文件的长度。
共享库的另外一个优点是:新版本的库替代老版本无需使用该库的程序重新连接编辑(只要接口不变的话)。
存储空间动态分配函数:
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
//函数返回值:成功返回非空指针,出错返回NULL
void free(void *ptr)
这些操作也是最容易出错的,并且出错之后很难查找那种。
alloca函数时在栈中申请存储空间的函数,有些情况下很有用的。
以上基本是进程运行环境。存储,变量,代码,地址。
标签:
原文地址:http://blog.csdn.net/u010518261/article/details/51925605