當內核執行C程序時,在調用main前先調用一個特殊的啓動例程。可執行程序文件將此啓動例程指定爲程序的起始地址。啓動例程從內核取得命令行參數和環境變量值,而後調用main函數。函數
存在8種方式終止進程:佈局
5種正常終止:spa
1. 從main返回命令行
2. 調用exit線程
3. 調用_exit或者_Exit指針
4. 最後一個線程從啓動例程中返回.code
5. 最後一個線程調用pthread_exit.對象
3種異常終止:進程
1. 調用abort內存
2. 接收信號並終止.
3. 最後一個線程對取消請求作出響應.
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
_exit和_Exit會立馬返回到內核, 而exit則會清除線程後返回內核.
在main函數中, 若是沒有顯式return/exit, 則默認返回0:
#include <stdio.h> int main(void) { printf("hello world\n"); }
終端輸出:
leicj@leicj:~/test$ ./a.out hello world leicj@leicj:~/test$ echo $? 0
一個進程能夠登記多達32個函數,這些函數將由exit自動調用。咱們稱這些函數爲終止處理程序,並調用atexit函數來登記這些函數。
終止處理程序:
#include <stdio.h> static void my_exit1(void); static void my_exit2(void); int main(void) { if (atexit( my_exit2 ) != 0) printf("can't register my_exit2\n"); if (atexit( my_exit1 ) != 0) printf("can't register my_exit1\n"); if (atexit( my_exit1 ) != 0) printf("can't register my_exit1\n"); printf("main is done\n"); return 0; } static void my_exit1(void) { printf("first exit handler\n"); } static void my_exit2(void) { printf("second exit handler\n"); }
程序輸出:
leicj@leicj:~/test$ ./a.out main is done first exit handler first exit handler second exit handler
1. 正文段:由CPU執行的機器指令部分
2. 初始化數據段:包含了程序中需明確的賦初值的變量
3. 非初始化數據段: 聲明在函數以外的變量存放的地方, 一般會被內核初始化爲0或者null.
4. 棧:自動變量以及每次函數調用時所需保存的信息都存放在此段中
5. 堆:進行動態分配
leicj@leicj:~/test$ size /usr/bin/cc /bin/sh text data bss dec hex filename 902577 8048 9696 920321 e0b01 /usr/bin/cc 143301 4792 11312 159405 26ead /bin/sh
ISO C定義三個函數用於分配內存, 一個函數用於釋放內存.
#include <stdlib.h>
void *malloc(size_t size);
void *calloc(size_t nobj, size_t size);
void *realloc(void *ptr, size_t newsize);
returns: 成功返回非空指針, 失敗返回NULL
void free(void *ptr);
malloc: 分配特定字節的內存, 初始值不肯定.
calloc: 分配特定數量的對象, 每一個對象的大小爲size.
realloc: 用於增長或減小內存.
#include <stdio.h> #include <stdlib.h> extern char *environ; int main( void ) { putenv("hello=world"); setenv("hello1", "world1", 0); printf("%s\n", getenv("hello")); printf("%s\n", getenv("hello1")); unsetenv("hello"); unsetenv("hello1"); return 0; }
程序輸出:
leicj@leicj:~/test$ ./a.out world world1
#include <stdio.h> #include <setjmp.h> jmp_buf jmpbuffer; void fun1(); void fun2(); int main( void ) { int bFun1 = 0; int bFun2 = 0; bFun1 = setjmp(jmpbuffer); bFun2 = setjmp(jmpbuffer); printf("the return value is:%d---%d\n", bFun1, bFun2); printf("main done\n"); if ( bFun1 || bFun2 ) { exit( 0 ); } fun1(); fun2(); return 0; } void fun1() { printf("fun1\n"); longjmp( jmpbuffer, 1 ); } void fun2() { printf("fun2\n"); longjmp( jmpbuffer, 2 ); }
程序輸出:
leicj@leicj:~/test$ ./a.out the return value is:0---0 main done fun1 the return value is:0---1 main done