main函數
- C程序總是從main函數開始執行。其原型是:
int main(int argc, char *argc[]);
/*argc是命令行參數的數目,argv是指向參數的各個指針所構成的數組*/
- 內核使程序執行的唯一方法是調用一個exec函數
進程終止
- 進程終止8種方式:
- 從main返回
- exit(自願)
- _exit或_Exit(自願)
- 最後一個線程從其啓動例程返回
- 從最後一個線程調用pthread_exit
- 調用abort
- 接收一個信號
- 最後一個線程對取消請求做出響應
請看如下經典的”hello world"程序
#include <stdio.h>
main()
{
printf("hello, world!\n");
}
以下是對該程序執行終止後的退出狀態碼的檢查
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ ./hello1
hello, world!
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ echo $?
14
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ gcc -std=c99 hello1.c
hello1.c:3:1: warning: return type defaults to ‘int’ [-Wimplicit-int]
main()
^
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ ./a.out
hello, world!
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ echo $?
0
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$
- 其終止碼是一個隨機的數 14
- 用1999 ISO C編譯器擴展,其終止碼總是爲0
#include <unistd.h>
void _exit(int status);
#include <stdlib.h>
void exit(int status);//輸出緩衝區中的所有數據都會被沖洗
void _Exit(int status);
//這些函數都沒有返回值,status就是進程終止狀態
- 一個進程可登記多至32個函數,在進程終止的時候,這些函數被調用,稱爲終止處理程序
#include <stdlib.h>
int atexit(void (*function)(void));
- 進程終止處理程序被調用的順序與他們被登記的順序剛好相反,請看如下實例
#include "apue.h"
static void my_exit1(void);
static void my_exit2(void);
int
main(void)
{
if (atexit(my_exit2) != 0)
err_sys("can't register my_exit2");
if (atexit(my_exit1) != 0)
err_sys("can't register my_exit1");
if (atexit(my_exit1) != 0)
err_sys("can't register my_exit1");
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");
}
執行結果如下
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$ ./doatexit
main is done
first exit handler
first exit handler
second exit handler
xiangke@xiangke-virtual-machine:/home/apue.3e/environ$
命令行參數
下面看一個顯示命令行參數的實例,如下:
#include "apue.h"
int
main(int argc, char *argv[])
{
int i;
/*for (i = 0; argv[i] != NULL; i++)*/
for (i = 0; i < argc; i++) /* echo all command-line args */
printf("argv[%d]: %s\n", i, argv[i]);
exit(0);
}
該實例運行結果如下
環境表
- 每個程序都接收到一張環境表,全局參數environ指向一個指針數組,該參數稱爲環境指針
extern char **environ
如下,是5個字符串組成的環境
每個字符串爲一個環境參數,其格式是name=value
C程序的存儲空間佈局
- 正文段,是CPU執行的機器指令部分。它是可共享的
- 初始化數據段,包含程序中明確賦值的變量
- 未初始化數據段,即bss(block started by symbol)
- 棧,自動變量和每次函數調用時所需保存的信息
- 堆。動態存儲分配
如下是一種存儲空間的典型分配方式
- 存放在磁盤程序文件中的段只有正文段和初始化數據段
- size命令可以報告正文段、數據段和bss段的長度,例如
共享庫
- 共享庫是公用函數的集合
- 它減少了可執行文件的長度
- 庫函數的版本升級不影響用該庫函數的程序
- 但是會增加程序運行時間開銷
存儲空間分配
以下說明3個用於存儲空間動態分配函數
#include <stdlib.h>
void *malloc(size_t size);
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
void *realloc(void *ptr, size_t size);
- 這三個函數返回的指針一定是適當對齊的,使其可用於任何數據對象
- realloc函數可以增、減以前分配的存儲區的長度
- 如果忘記用free 釋放存儲空間,會使進程佔用的存儲空間連續增加,這被稱爲內存泄漏
環境變量
#include <stdlib.h>
//取得環境變量的值
char *getenv(const char *name);
int putenv(char *string);//添加或改變環境變量的值
int setenv(const char *name, const char *value, int overwrite);//添加環境變量,overwrite!=0,則覆蓋已存在的環境變量的值,否則不改變
int unsetenv(const char *name)//刪除環境變量