- 論壇徽章:
- 36
|
對于很多初學(xué)《UNIX環(huán)境高級編程》(AdvancedProgramming in the UNIX Environment,簡稱APUE,以下使用簡稱)的朋友,第一個(gè)遇到的問題可能就是該書中的源代碼編譯的問題。此書中差不多每個(gè)例程中,都會(huì)有這樣一行源碼:
#include "ourhdr.h"
在第二版中改為:
#include "apue.h"
這個(gè)頭文件是作者把把每個(gè)例程中常用的標(biāo)準(zhǔn)頭文件,一些常用的出錯(cuò)處理函數(shù)(err_**()之類的函數(shù))和一些常用的宏定義給整理在一個(gè)頭文件中。這個(gè)可以省去在每個(gè)例程中錄入較多的重復(fù)代碼,這樣可以減少每個(gè)例程的長度。但是,這樣就給讀者帶來了不少麻煩。因?yàn)槲覀冞要去搞明白如和把這個(gè)頭文件編譯,然后做成庫文件,添加到我們的系統(tǒng)中。特別讀于初學(xué)者,本來滿懷信心的,結(jié)果在編譯第一個(gè)程序的時(shí)候就出現(xiàn)了問題。我也沒有搞明白如何把"ourhdr.h"靜態(tài)的編譯到系統(tǒng)中。
不過,不明白如何使用"ourhdr.h"這個(gè)頭文件,并不會(huì)影響我們學(xué)習(xí)APUE,也不會(huì)影響我們編譯和運(yùn)行每一個(gè)例程。其實(shí),簡單的想一下,如果一個(gè)C程序要能順利的編譯和運(yùn)行,除了我們要語法正確等方面外,最根本的是要保證我們程序中所調(diào)用的函數(shù)以及宏等等都要有完整的來源,也就是必須包含所有調(diào)用函數(shù)和宏所在的頭文件。對于一個(gè)具體的源程序,如果我們正確的包含了頭文件,那么剩下的就是程序本生語法方面應(yīng)該注意的事項(xiàng)。
如何確定系統(tǒng)調(diào)用函數(shù)包含在那個(gè)頭文件中呢?這在Unix/Linux系統(tǒng)下并非一件難事。Unix/Linux下命令man可以幫助我們找到。man命令不僅可以幫助我們查找一般命令的用法,同時(shí)提供不同層次的幫助諸如系統(tǒng)調(diào)用或者管理員級別的命令等等(譬如FreeBSD6.1中,man1是用戶專用手冊,man 2是系統(tǒng)調(diào)用,man 3是庫函數(shù)查詢等等)。
下面我們就以APUE書中程序1-1(實(shí)現(xiàn)ls命令部分功能)為例,來說明如何將書中的程序改編成全部使用標(biāo)準(zhǔn)頭文件的程序。其中,操作系統(tǒng)用的是FreeBSD6.1,經(jīng)過相應(yīng)的修改可以在書中所說的幾個(gè)Unix系統(tǒng)及Linux系統(tǒng)中運(yùn)行,我也曾在Debian Linux下成功編譯和運(yùn)行該程序。書中1-1.c的原始代碼如下:
#include <sys/types.h>
#include <dirent.h>
#include "ourhdr.h"
int
main(int argc, char *argv[])
{
DIR *dp;
struct dirent *dirp;
if (argc != 2)
err_quit("usage: ls directory_name");
if ((dp = opendir(argv[1])) == NULL)
err_sys("can't open %s", argv[1]);
while ((dirp = readdir(dp)) != NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
exit(0);
} |
從書后面的附錄中可以看到"ourhdr.h"的內(nèi)容比較多,包含了比較多的常用頭文件,一些宏定義和一些常用函數(shù)和出錯(cuò)函數(shù)的定義。其實(shí),對于每一個(gè)具體的程序,我們只需要找到該程序中用到的頭文件即可。
該1-1.c中所用到的系統(tǒng)函數(shù)調(diào)用有:opnedir(),readdir(),printf(),closedir()和exit()。
其中,對于常用的函數(shù)prinft()和exit(),它們所在的頭文件一般都知道,分別是<stdio.h>和<stdlib.h>。而對于opnedir(),readdir()和closedir(),我們可以通過man opendir,man readdir,manclosedir得到這三個(gè)關(guān)于目錄操作的函數(shù)所在的頭文件都是:<sys/types.h>和<dirent.h>。這兩個(gè)頭文件在源程序中也已經(jīng)列出。
其次,1-1.c中還用到了作者自定義的兩個(gè)函數(shù):err_quit()和err_sys()。這兩個(gè)函數(shù)主要使用來進(jìn)行出錯(cuò)處理的。當(dāng)然,使用這兩個(gè)函數(shù)對錯(cuò)誤信息的處理是比較完善的。但是,作為我們學(xué)習(xí)來講,了解程序的核心功能是首要的,我們可以將出錯(cuò)處理簡化一點(diǎn),即當(dāng)遇到錯(cuò)誤的時(shí)候,我們只簡單的使用printf()函數(shù)來提示一下有錯(cuò)誤發(fā)生。當(dāng)然,用printf()來進(jìn)行出錯(cuò)處理并不是一種很合理的方法,而且往往我們看不到更關(guān)鍵的錯(cuò)誤信息,但對于我們僅僅作為學(xué)習(xí)來用還是可以接受的。畢竟我們要理解的核心部分是程序的功能實(shí)現(xiàn),出錯(cuò)處理在于其次。
通過以上的說明,我們可以將1-1.c修改為如下內(nèi)容:
#include <sys/types.h>
#include <dirent.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
DIR *dp;
struct dirent *dirp;
if(argc != 2)
{
printf("You need input the directory name.\n");
exit(1);
}
if((dp = opendir(argv[1])) == NULL)
{
printf("cannot open %s\n", argv[1]);
exit(1);
}
while ((dirp = readdir(dp)) != NULL)
printf("%s\n", dirp->d_name);
closedir(dp);
exit(0);
}
|
這樣修改后的程序已經(jīng)與作者的頭文件"ourhdr.h"沒有關(guān)系,可以單獨(dú)的進(jìn)行編譯。我使用的是root用戶,執(zhí)行命令:
# gcc 1-1.c //生成目標(biāo)文件a.out
或者
# gcc -o 1-1 1-1.c //生成目標(biāo)文件1-1
沒有任何錯(cuò)誤和警告,說明編譯成功。這時(shí)我們執(zhí)行生成的目標(biāo)文件:
# ./a.out /home
或者
# ./1-1 /home
則會(huì)列出/home路徑下的所有文件,包括目錄(.)和(..)。
通過這樣的方法,基本上我們可以將該書中所有的例程修改成不包含"ourhdr.h"的程序。這樣,我們就可以單獨(dú)的編譯每一個(gè)例程,而不用顧及作者所給的雜湊的頭文件。同時(shí)這種比較笨的方法,反而有利于幫助我們了解不同系統(tǒng)調(diào)用所對應(yīng)的頭文件,對于學(xué)習(xí)來說,這應(yīng)該是一件好事。
歡迎交流,歡迎自由轉(zhuǎn)載,但請注明CU鏈接或本人CU Blog鏈接:
http://blog.chinaunix.net/u/33048/showart_343553.html
[ 本帖最后由 Godbach 于 2007-8-21 14:04 編輯 ] |
評分
-
查看全部評分
|