<Uinx 环境高级编程笔记>
当执行程序时,main函数时如何被调用的?
C程序总是从main函数开始执行。当内核在启动C程序时,在调用main之前先调用一个特殊的启动例程。可执行程序将
次启动例程指定为程序的起始地址 -- 这是由连接编辑程序设置的,而连接编辑程序则由C编译程序调用。启动例程从
内核取得命令行参数和环境变量,然后为调用main函数做好安排。
进程的终止
1 正常终止
a) 从main返回 b)调用exit c)调用_exit
exit先执行一些清理再进入内核。
2 异常终止
a) 调用abort b)由一个信号终止
在程序终止前可以调用其它函数,这可以通过int atexit (void (*function)(void));来设置程序正常结束前
调用的程序。最多可以登记32个这样的函数。如果有多个,则以登记相反的顺序来调用这些函数。这样的
函数通常被称为终止处理程序。
内核使程序执行的唯一方法是调用一个exec函数。进程自愿终止的唯一方法是显示或隐式地调用exit函数。
环境表
每个程序都接收一张环境表。可以如下访问环境表
extern char **environ;
for (int i=0; environ[i]; i++)
printf("%s\n", environ[i]);
C程序的存储空间布局
正文段。程序本身,这是又CPU执行的机器指令部分。
初始化数据段。包含了程序中需赋初值的变量。
非初始数据段。包含未初始化的变量。
linux上测试好像不是这样的:
char a=2;
char b;
char c=3;
printf("a:%x b:%x c:%x\n", &a, &b, &c);
输出为:a:bfef9b8f b:bfef9b8e c:bfef9b8d
可见a, c并没有放在一起。
栈
堆
size命令报告正文段、数据段和bss段的长度。
共享库
共享库使得可执行文件中不再需要包含常用的库函数(比如C标准库),这将大大减少可执行文件的长度。同时
共享库还便于库函数的版本更新,可以动态替换。
ldd 命令可一查看可执行文件依赖的库。
环境变量
存取环境变量的API
char * getenv(const char *name);
int putenv(const char * string);
int setenv(const char *name,const char * value,int overwrite);