1.程序的运行
每个程序在运行main函数之前,都会有一个start-up routine运行。这个程序的地址在链接的时候,由链接器将它的地址写入程序的起始地址。这个程序会将命令行变量与环境变量准备好,再调用main函数。
2.程序的终止
有以下几种方式令一个程序退出:
1.从main函数中return
2.调用 exit
3.调用 _exit 或者 _Exit
4.从最后一个线程中返回
5.最后一个线程调用 pthread_exit
或者是以下几种不正常的退出:
6.调用 abort
7.接收到一个信号
8.最后一个线程中接收到一个取消的请求。
exit函数会对所有打开的stream调用fclose来关闭文件。查看程序的返回码:"echo $?"
在ISO C中说明,每个进程可以绑定32个函数在程序退出时进行调用。可以使用atexit函数进行绑定,绑定的函数,没有参数,也不需要
返回结果。在进程退出时,以绑定的反向顺序进行调用。exit程序将首先调用这些函数,再清空所有的文件流。
进程运行的时序图如下:
3.环境变量
程序会将环境变量以字符串数组的形式传入,可以用environ这个变量来访问,结构如下图:
每个环境变量都采用 name = value 的字符串形式进行存储。
可以通过 getenv 函数进行环境变量的访问,可以通过 putenv , setenv , unsetenv来操作环境变量。但只能对所在的进程与子进程产生影响。
4.程序的组织
每个程序都有以下几个模块:
1.text,可以运行代码段,保持只读,防止被不小心修改。这一部分会保存在程序文件中。
2.initialized data , 已经被初始化的数据段,这一部分也会保存在程序文件中,在程序调用时读入。
3.uninitialized data (bss),这一部分的数据没有被程序初始化,在程序调用时,会被系统初始化为0或者null
4.stack , 栈 , 自动型变量会保存在栈中,同时函数调用的相关信息也会保存在栈中。
5.heap, 堆 , 动态内存分配的变量保存的位置。
使用动态库,可以使得程序的大小减少,同时方便地更新使用代码。
5.内存分配与释放
内存通常可以使用以下的函数进行分配:
5.1 malloc ,这个函数分配内存,但是并不对分配的内存进行初始化;
5.2 calloc , 这个函数可以分配内存,但同时会对内存进行初始化,每个字节都会初始化为0。
5.3 realloc , 这个函数可以扩展之前分配的内存的大小。与STL中的操作一样,如果所在的空间无法再扩展了,
则会造成大量的内存拷贝。
使用完毕的内存,可以使用free函数来进行释放。这个函数会将内存释放到malloc的可用内存池,等待下次分配,而不是将内存返回给内核。
每次分配的内存都会额外存储一些相关的信息,如果写入内存时,超越了边界,将有可能破坏了这些信息,导致内存错误。
6.使用setjmp与longjmp进行跳转
当使用longjmp进行跳转的时候,stack将会回退至setjmp的情况,所以保存在stack中的变量与相关信息都会被系统抛弃。但是声明为volatile,global与static的变量都会