1.main函數
c程序總是從main函數開始執行的,其原型是
int main(int argc, char **argv);
//argc是命令行參數的個數
//argv是指向參數的各個指針所構成的數組
2.進程終止
有8種方式可以讓進程終止,其中前5種爲正常終止
1.從main返回
2.調用exit
3.調用_exit或_Exit
4.最後一個線程從其啓動例程返回
5.最後一個線程調用pthread_exit
6.調用abort
7.接到一個信號並終止
8.最後一個線程對取消請求做出響應
3.exit函數
#include <stdlib.h>
void exit(int status);
void _Exit(int status);
#include <unistd.h>
void _exit(int status);
//_exit和_Exit立即進入內核,exit則進行一些清理處理在進入內核
由於歷史原因,exit函數總是要執行一個標準I/O庫的清理關閉操作fclose(),這將造成所有的緩衝區數據都被沖洗
unix shell:#echo $? 可以顯示程序的返回值
4.atexit函數
按照ISO C規定,一個進程可以登記多達32個函數,這些函數將由exit自動調用。
我們稱這些函數爲終止處理函數,用下面的函數來登記這些函數:
#include <stdlib.h>
int atexit(void (*func)(void));
//成功返回0,出錯返回非零值
在程序即將結束的時候,調用登記過的函數,但是函數的執行順序和登記的順序是相反的
根據ISO C和POSIX.2,exit函數首先調用各個終止處理函數,然後按需多次調用fclose函數,關閉所有打開的流。
POSIX.1擴展了ISO C的標準,它指定如若程序調用exec函數族的任一函數,則將清除所有已安裝的終止處理函數。
5.命令行參數
當執行一個程序的時候,調用exec的進程可將命令行參數傳遞給新程序。
程序如下:
- #include <stdio.h>
- #include <stdlib.h>
- int main(int argc, char **argv)
- {
- int i;
- for (i = 0; i < argc; i++) {
- printf("argv[%d] = %s.\n", i, argv[i]);
- }
- exit(EXIT_SUCCESS);
- }
6.環境表
每個程序都會接受一張環境表,這個表和參數表一樣是一個字符指針數組,每個指針包含以NULL介紹給有的c字符串的地址
在程序中聲明
extern char **environ;
在程序中輸出環境表
for (i = 0; environ[i] != NULL; i++) {
printf("environ[%d]: %s.\n", i, environ[i]);
}
環境表的每個字段的格式都是name=value
7.c語言的存儲空間佈局
從歷史上將c語言一直由以下幾部分組成
正文段:這是由CPU執行的機器指令部分。正文段是共享的,在存儲器中只有一個副本。另外正文段通常是隻讀的
初始化數據段: 通常將此段稱爲數據段,它包含了程序中需明確的賦初值的變量。如:
c語言中:
int i = 0;
此變量存在初始化數據段中
非初始化數據段:通常將此段稱爲bss段。在程序開始執行之前,內核將此段中的數據初始化爲0或空指針。
棧:自動變量以及每次函數調用時所需保存的信息都存放在此段中。每次調用函數時,其返回地址以及調用者的環
境信息都存放到棧中。然後,最近被調用的函數在棧上爲其自動和臨時變量分配存儲空間。通過這種方式使用棧,
可以遞歸調用c函數。遞歸函數每次調用自身時,就使用一個新的棧幀,因此一個函數調用實例中的環境變量不會
影響到另一個函數調用實例中的變量。
堆:通常在堆中進行動態存儲分配。堆位於非初始化數據段和棧之間。
size命令則報告正文段,數據段和bss段的長度
8.存儲器分配
ISO C說明了三種用於存儲器空間分配的函數
#include <stdlib.h>
void *malloc(size_t size);
//分配指定字節數的存儲區。此存儲區中的初始值不確定。
void *calloc(size_t nobj, size_t size);
//在內存的動態存儲區中分配nobj個長度爲size的連續空間,存儲區中初始值均爲0。
void *realloc(void *ptr, size_t newsize);
//將ptr所指向的存儲區重新分配,當增加長度的時候新增的存取區中的初始值不確定。
//這三個函數若成功返回非空指針,失敗返回NULL
void free(void *ptr);
//釋放存儲區空間
9.setjmp和longjmp
在c語言中,goto語句是不能跨越函數的,最穩妥安全的跨越函數跳轉的函數是setjmp和longjmp
#include <setjmp.h>
int setjmp(jmp_buf env);
//若直接調用返回0,若從longjmp調用返回非0值
void longjmp(jmp_buf env, int val);
//setjmp設置返回的位置,longjmp中的val是跳轉後的返回值