本章介紹系統編程的基礎概念和一些后續章節用到的函數及頭文件,並說明了可移植性問題。
系統調用是受控的內核入口,通過系統調用,進程可以請求內核以自己的名義去執行某些動作,比如創建子進程,執行I/O操作,進行進程間的通信等。
系統調用與C語言的函數調用類似。但是系統調用的過程比C語言函數調用復雜,開銷也大得多。
Linux 的系統調用通過 int 0x80 實現,用系統調用號來區分入口函數。操作系統實現系統調用的基本過程是:
應用程序調用庫函數(API);
API 將系統調用號存入 EAX,然后通過中斷調用使系統進入內核態;
內核中的中斷處理函數根據系統調用號,調用對應的內核函數(系統調用);
系統調用完成相應功能,將返回值存入 EAX,返回到中斷處理函數;
中斷處理函數返回到 API 中;
API 將 EAX 返回給應用程序。
本章后續部分重點介紹了后面章節所要使用的頭文件及其實現,主要如下:
ename.c.inc
error_functions.h
get_num.h
tlpi_hdr.h
其中ename.c.inc文件定義了一個字符串數組,用於對應錯誤碼的名稱。
error_functions.h文件聲明了本書自定義的錯誤處理函數。
get_num.h文件聲明了本書自定義的數值提取函數。
tlpi_hdr.h文件則包含了后續需用到的系統調用頭文件。
由於存在3個頭文件以及2個實現,每次編譯時必須對實現也進行編譯,為方便后續學習,采用將頭文件復制到默認的編譯器尋找目錄下,並將實現打包成靜態庫,然后使用別名來默認鏈接靜態庫。
以Debian/Ubuntu為例,具體操作如下:
第一步:下載本書所給的源碼文件
wget "http://man7.org/tlpi/code/download/tlpi-161214-dist.tar.gz"
或者點此下載
第二步:解壓后,make編譯
tar -zxvf tlpi-161214-dist.tar.gz cd tlpi-dist/ make -j
第三步:拷貝頭文件至系統目錄
cd lib/ sudo cp tlpi_hdr.h /usr/local/include/ sudo cp get_num.h /usr/local/include/ sudo cp error_functions.h /usr/local/include/ sudo cp ename.c.inc /usr/local/include/
第四步:制作靜態庫文件
g++ -c get_num.c error_functions.c ar -crv libtlpi.a get_num.o error_functions.o sudo cp libtlpi.a /usr/local/lib
第五步:簡化編譯命令
alias gl++='new() { g++ $1 -ltlpi;}; new'
第五步需要在當前用戶的主目錄下的.bashrc文件中設置別名,由於alias不支持參數,因此需要使用函數來間接實現,並且接受一個參數$1以指定對某個源文件進行編譯並鏈接之前的靜態庫libtlpi.a。配置完畢后重新讀入.bashrc文件以生效。這里使用函數來接受一個參數存在一個缺點即只能使用一個命令行參數,多余參數將被忽略。
完成上面的步驟后,即可使用快捷命令來編譯我們的程序了:
gl++ main.cpp
該命令將編譯生成a.out文件。
如果不想使用第五步來簡化,則每次編譯手動來鏈接庫,命令如下:
g++ main.cpp -o main -ltlpi
