linux下C編程高效手冊(cè)

上傳人:zh****u6 文檔編號(hào):34810553 上傳時(shí)間:2021-10-23 格式:DOC 頁(yè)數(shù):76 大?。?60.01KB
收藏 版權(quán)申訴 舉報(bào) 下載
linux下C編程高效手冊(cè)_第1頁(yè)
第1頁(yè) / 共76頁(yè)
linux下C編程高效手冊(cè)_第2頁(yè)
第2頁(yè) / 共76頁(yè)
linux下C編程高效手冊(cè)_第3頁(yè)
第3頁(yè) / 共76頁(yè)

下載文檔到電腦,查找使用更方便

30 積分

下載資源

還剩頁(yè)未讀,繼續(xù)閱讀

資源描述:

《linux下C編程高效手冊(cè)》由會(huì)員分享,可在線閱讀,更多相關(guān)《linux下C編程高效手冊(cè)(76頁(yè)珍藏版)》請(qǐng)?jiān)谘b配圖網(wǎng)上搜索。

1、 1)Linux程序設(shè)計(jì)入門--基礎(chǔ)知識(shí) Linux下C語(yǔ)言編程基礎(chǔ)知識(shí) 前言: 這篇文章介紹在LINUX下進(jìn)行C語(yǔ)言編程所需要的基礎(chǔ)知識(shí).在這篇文章當(dāng)中,我們將 會(huì)學(xué)到以下內(nèi)容: 源程序編譯 Makefile的編寫 程序庫(kù)的鏈接 程序的調(diào)試 頭文件和系統(tǒng)求助 ---------------------------------------------------------------------------- ---- 1.源程序的編譯 在Linux下面,如果要編譯一個(gè)C語(yǔ)言源程序,我們要使用GNU的gcc編譯器. 下面我們 以一個(gè)實(shí)例來(lái)

2、說(shuō)明如何使用gcc編譯器. 假設(shè)我們有下面一個(gè)非常簡(jiǎn)單的源程序(hello.c): int main(int argc,char **argv) { printf("Hello Linux\n"); } 要編譯這個(gè)程序,我們只要在命令行下執(zhí)行: gcc -o hello hello.c gcc 編譯器就會(huì)為我們生成一個(gè)hello的可執(zhí)行文件.執(zhí)行./hello就可以看到程序的輸出 結(jié)果了.命令行中 gcc表示我們是用gcc來(lái)編譯我們的源程序,-o 選項(xiàng)表示我們要求編譯 器給我們輸出的可執(zhí)行文件名為hello 而hello.c是我們的源程序文件. gcc編譯器有許多選項(xiàng),一

3、般來(lái)說(shuō)我們只要知道其中的幾個(gè)就夠了. -o選項(xiàng)我們已經(jīng)知道 了,表示我們要求輸出的可執(zhí)行文件名. -c選項(xiàng)表示我們只要求編譯器輸出目標(biāo)代碼,而 不必要輸出可執(zhí)行文件. -g選項(xiàng)表示我們要求編譯器在編譯的時(shí)候提供我們以后對(duì)程序 進(jìn)行調(diào)試的信息. 知道了這三個(gè)選項(xiàng),我們就可以編譯我們自己所寫的簡(jiǎn)單的源程序了,如果你想要知道更 多的選項(xiàng),可以查看gcc的幫助文檔,那里有著許多對(duì)其它選項(xiàng)的詳細(xì)說(shuō)明. 2.Makefile的編寫 假設(shè)我們有下面這樣的一個(gè)程序,源代碼如下: /* main.c */ #include "mytool1.h" #include "

4、mytool2.h" int main(int argc,char **argv) { mytool1_print("hello"); mytool2_print("hello"); } /* mytool1.h */ #ifndef _MYTOOL_1_H #define _MYTOOL_1_H void mytool1_print(char *print_str); #endif /* mytool1.c */ #include "mytool1.h" void mytool1_print(char *print_str) { printf("This is

5、mytool1 print %s\n",print_str); } /* mytool2.h */ #ifndef _MYTOOL_2_H #define _MYTOOL_2_H void mytool2_print(char *print_str); #endif /* mytool2.c */ #include "mytool2.h" void mytool2_print(char *print_str) { printf("This is mytool2 print %s\n",print_str); } 當(dāng)然由于這個(gè)程序是很短的我們可以這樣來(lái)編譯 gcc -

6、c main.c gcc -c mytool1.c gcc -c mytool2.c gcc -o main main.o mytool1.o mytool2.o 這樣的話我們也可以產(chǎn)生main程序,而且也不時(shí)很麻煩.但是如果我們考慮一下如果有一 天我們修改了其中的一個(gè)文件(比如說(shuō)mytool1.c)那么我們難道還要重新輸入上面的命令 ?也許你會(huì)說(shuō),這個(gè)很容易解決啊,我寫一個(gè)SHELL腳本,讓她幫我去完成不就可以了.是的 對(duì)于這個(gè)程序來(lái)說(shuō),是可以起到作用的.但是當(dāng)我們把事情想的更復(fù)雜一點(diǎn),如果我們的程 序有幾百個(gè)源程序的時(shí)候,難道也要編譯器重新一個(gè)一個(gè)的去編譯? 為此,聰明的

7、程序員們想出了一個(gè)很好的工具來(lái)做這件事情,這就是make.我們只要執(zhí)行以 下make,就可以把上面的問(wèn)題解決掉.在我們執(zhí)行make之前,我們要先編寫一個(gè)非常重要的 文件.--Makefile.對(duì)于上面的那個(gè)程序來(lái)說(shuō),可能的一個(gè)Makefile的文件是: # 這是上面那個(gè)程序的Makefile文件 main:main.o mytool1.o mytool2.o gcc -o main main.o mytool1.o mytool2.o main.o:main.c mytool1.h mytool2.h gcc -c main.c mytool1.o:mytool1.c myto

8、ol1.h gcc -c mytool1.c mytool2.o:mytool2.c mytool2.h gcc -c mytool2.c 有了這個(gè)Makefile文件,不過(guò)我們什么時(shí)候修改了源程序當(dāng)中的什么文件,我們只要執(zhí)行 make命令,我們的編譯器都只會(huì)去編譯和我們修改的文件有關(guān)的文件,其它的文件她連理 都不想去理的. 下面我們學(xué)習(xí)Makefile是如何編寫的. 在Makefile中也#開(kāi)始的行都是注釋行.Makefile中最重要的是描述文件的依賴關(guān)系的說(shuō) 明.一般的格式是: target: components TAB rule 第一行表示的是依賴關(guān)系.第二行是

9、規(guī)則. 比如說(shuō)我們上面的那個(gè)Makefile文件的第二行 main:main.o mytool1.o mytool2.o 表示我們的目標(biāo)(target)main的依賴對(duì)象(components)是main.o mytool1.o mytool2.o 當(dāng)倚賴的對(duì)象在目標(biāo)修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們的上 面那個(gè)Makefile第三行所說(shuō)的一樣要執(zhí)行 gcc -o main main.o mytool1.o mytool2.o 注意規(guī)則一行中的TAB表示那里是一個(gè)TAB鍵 Makefile有三個(gè)非常有用的變量.分別是$@,$^,$<代表的意義分別是: $

10、@--目標(biāo)文件,$^--所有的依賴文件,$<--第一個(gè)依賴文件. 如果我們使用上面三個(gè)變量,那么我們可以簡(jiǎn)化我們的Makefile文件為: # 這是簡(jiǎn)化后的Makefile main:main.o mytool1.o mytool2.o gcc -o $@ $^ main.o:main.c mytool1.h mytool2.h gcc -c $< mytool1.o:mytool1.c mytool1.h gcc -c $< mytool2.o:mytool2.c mytool2.h gcc -c $< 經(jīng)過(guò)簡(jiǎn)化后我們的Makefile是簡(jiǎn)單了一點(diǎn),不過(guò)人們有時(shí)候還想簡(jiǎn)

11、單一點(diǎn).這里我們學(xué)習(xí) 一個(gè)Makefile的缺省規(guī)則 ..c.o: gcc -c $< 這個(gè)規(guī)則表示所有的 .o文件都是依賴與相應(yīng)的.c文件的.例如mytool.o依賴于mytool.c 這樣Makefile還可以變?yōu)? # 這是再一次簡(jiǎn)化后的Makefile main:main.o mytool1.o mytool2.o gcc -o $@ $^ ..c.o: gcc -c $< 好了,我們的Makefile 也差不多了,如果想知道更多的關(guān)于Makefile規(guī)則可以查看相應(yīng)的 文檔. 3.程序庫(kù)的鏈接 試著編譯下面這個(gè)程序 /* temp.c */

12、 #include ; int main(int argc,char **argv) { double value; printf("Value:%f\n",value); } 這個(gè)程序相當(dāng)簡(jiǎn)單,但是當(dāng)我們用 gcc -o temp temp.c 編譯時(shí)會(huì)出現(xiàn)下面所示的錯(cuò)誤. /tmp/cc33Kydu.o: In function `main: /tmp/cc33Kydu.o(.text+0xe): undefined reference to `log collect2: ld returned 1 exit status 出現(xiàn)這個(gè)錯(cuò)誤是因?yàn)榫幾g器

13、找不到log的具體實(shí)現(xiàn).雖然我們包括了正確的頭文件,但是我 們?cè)诰幾g的時(shí)候還是要連接確定的庫(kù).在Linux下,為了使用數(shù)學(xué)函數(shù),我們必須和數(shù)學(xué)庫(kù) 連接,為此我們要加入 -lm 選項(xiàng). gcc -o temp temp.c -lm這樣才能夠正確的編譯.也許 有人要問(wèn),前面我們用printf函數(shù)的時(shí)候怎么沒(méi)有連接庫(kù)呢?是這樣的,對(duì)于一些常用的函 數(shù)的實(shí)現(xiàn),gcc編譯器會(huì)自動(dòng)去連接一些常用庫(kù),這樣我們就沒(méi)有必要自己去指定了. 有時(shí) 候我們?cè)诰幾g程序的時(shí)候還要指定庫(kù)的路徑,這個(gè)時(shí)候我們要用到編譯器的 -L選項(xiàng)指定 路徑.比如說(shuō)我們有一個(gè)庫(kù)在 /home/hoyt/mylib下,這樣我們編譯

14、的時(shí)候還要加上 -L/h ome/hoyt/mylib.對(duì)于一些標(biāo)準(zhǔn)庫(kù)來(lái)說(shuō),我們沒(méi)有必要指出路徑.只要它們?cè)谄鹑笔?kù)的路 徑下就可以了.系統(tǒng)的缺省庫(kù)的路徑/lib /usr/lib /usr/local/lib 在這三個(gè)路徑下面 的庫(kù),我們可以不指定路徑. 還有一個(gè)問(wèn)題,有時(shí)候我們使用了某個(gè)函數(shù),但是我們不知道庫(kù)的名字,這個(gè)時(shí)候怎么辦呢 ?很抱歉,對(duì)于這個(gè)問(wèn)題我也不知道答案,我只有一個(gè)傻辦法.首先,我到標(biāo)準(zhǔn)庫(kù)路徑下面去 找看看有沒(méi)有和我用的函數(shù)相關(guān)的庫(kù),我就這樣找到了線程(thread)函數(shù)的庫(kù)文件(libp thread.a). 當(dāng)然,如果找不到,只有一個(gè)笨方法.比如我要找si

15、n這個(gè)函數(shù)所在的庫(kù). 就只 好用 nm -o /lib/*.so|grep sin>;~/sin 命令,然后看~/sin文件,到那里面去找了. 在s in文件當(dāng)中,我會(huì)找到這樣的一行l(wèi)ibm-2.1.2.so:00009fa0 W sin 這樣我就知道了sin在 libm-2.1.2.so庫(kù)里面,我用 -lm選項(xiàng)就可以了(去掉前面的lib和后面的版本標(biāo)志,就剩 下m了所以是 -lm). 如果你知道怎么找,請(qǐng)趕快告訴我,我回非常感激的.謝謝! 4.程序的調(diào)試 我們編寫的程序不太可能一次性就會(huì)成功的,在我們的程序當(dāng)中,會(huì)出現(xiàn)許許多多我 們想不到的錯(cuò)誤,這個(gè)時(shí)候我們

16、就要對(duì)我們的程序進(jìn)行調(diào)試了. 最常用的調(diào)試軟件是gdb.如果你想在圖形界面下調(diào)試程序,那么你現(xiàn)在可以選擇xxgdb.記 得要在編譯的時(shí)候加入 -g選項(xiàng).關(guān)于gdb的使用可以看gdb的幫助文件.由于我沒(méi)有用過(guò)這 個(gè)軟件,所以我也不能夠說(shuō)出如何使用. 不過(guò)我不喜歡用gdb.跟蹤一個(gè)程序是很煩的事情 ,我一般用在程序當(dāng)中輸出中間變量的值來(lái)調(diào)試程序的.當(dāng)然你可以選擇自己的辦法,沒(méi)有 必要去學(xué)別人的.現(xiàn)在有了許多IDE環(huán)境,里面已經(jīng)自己帶了調(diào)試器了.你可以選擇幾個(gè)試 一試找出自己喜歡的一個(gè)用. 5.頭文件和系統(tǒng)求助 有時(shí)候我們只知道一個(gè)函數(shù)的大概形式,不記得確切的表達(dá)式,

17、或者是不記得著函數(shù) 在那個(gè)頭文件進(jìn)行了說(shuō)明.這個(gè)時(shí)候我們可以求助系統(tǒng). 比如說(shuō)我們想知道fread這個(gè)函數(shù)的確切形式,我們只要執(zhí)行 man fread 系統(tǒng)就會(huì)輸出著 函數(shù)的詳細(xì)解釋的.和這個(gè)函數(shù)所在的頭文件;說(shuō)明了. 如果我們要write這個(gè)函 數(shù)的說(shuō)明,當(dāng)我們執(zhí)行man write時(shí),輸出的結(jié)果卻不是我們所需要的. 因?yàn)槲覀円氖莣 rite這個(gè)函數(shù)的說(shuō)明,可是出來(lái)的卻是write這個(gè)命令的說(shuō)明.為了得到write的函數(shù)說(shuō)明 我們要用 man 2 write. 2表示我們用的write這個(gè)函數(shù)是系統(tǒng)調(diào)用函數(shù),還有一個(gè)我們常 用的是3表示函數(shù)是C的庫(kù)函數(shù).

18、記住不管什么時(shí)候,man都是我們的最好助手. ------------------------------------------------------------------------ 好了,這一章就講這么多了,有了這些知識(shí)我們就可以進(jìn)入激動(dòng)人心的Linux下的C程序探 險(xiǎn)活動(dòng). 2)Linux程序設(shè)計(jì)入門--進(jìn)程介紹 Linux下進(jìn)程的創(chuàng)建 前言: 這篇文章是用來(lái)介紹在Linux下和進(jìn)程相關(guān)的各個(gè)概念.我們將會(huì)學(xué)到: 進(jìn)程的概念 進(jìn)程的身份 進(jìn)程的創(chuàng)建 守護(hù)進(jìn)程的創(chuàng)建 ---------------------------------

19、------------------------------------------- ---- 1。進(jìn)程的概念 Linux操作系統(tǒng)是面向多用戶的.在同一時(shí)間可以有許多用戶向操作系統(tǒng)發(fā)出各種命 令.那么操作系統(tǒng)是怎么實(shí)現(xiàn)多用戶的環(huán)境呢? 在現(xiàn)代的操作系統(tǒng)里面,都有程序和進(jìn)程 的概念.那么什么是程序,什么是進(jìn)程呢? 通俗的講程序是一個(gè)包含可以執(zhí)行代碼的文件 ,是一個(gè)靜態(tài)的文件.而進(jìn)程是一個(gè)開(kāi)始執(zhí)行但是還沒(méi)有結(jié)束的程序的實(shí)例.就是可執(zhí)行文 件的具體實(shí)現(xiàn). 一個(gè)程序可能有許多進(jìn)程,而每一個(gè)進(jìn)程又可以有許多子進(jìn)程.依次循環(huán) 下去,而產(chǎn)生子孫進(jìn)程. 當(dāng)程序被系統(tǒng)調(diào)用到

20、內(nèi)存以后,系統(tǒng)會(huì)給程序分配一定的資源(內(nèi) 存,設(shè)備等等)然后進(jìn)行一系列的復(fù)雜操作,使程序變成進(jìn)程以供系統(tǒng)調(diào)用.在系統(tǒng)里面只 有進(jìn)程沒(méi)有程序,為了區(qū)分各個(gè)不同的進(jìn)程,系統(tǒng)給每一個(gè)進(jìn)程分配了一個(gè)ID(就象我們的 身份證)以便識(shí)別. 為了充分的利用資源,系統(tǒng)還對(duì)進(jìn)程區(qū)分了不同的狀態(tài).將進(jìn)程分為新 建,運(yùn)行,阻塞,就緒和完成五個(gè)狀態(tài). 新建表示進(jìn)程正在被創(chuàng)建,運(yùn)行是進(jìn)程正在運(yùn)行,阻 塞是進(jìn)程正在等待某一個(gè)事件發(fā)生,就緒是表示系統(tǒng)正在等待CPU來(lái)執(zhí)行命令,而完成表示 進(jìn)程已經(jīng)結(jié)束了系統(tǒng)正在回收資源. 關(guān)于進(jìn)程五個(gè)狀態(tài)的詳細(xì)解說(shuō)我們可以看《操作系 統(tǒng)》上面有詳細(xì)的解說(shuō)。 2。進(jìn)

21、程的標(biāo)志 上面我們知道了進(jìn)程都有一個(gè)ID,那么我們?cè)趺吹玫竭M(jìn)程的ID呢?系統(tǒng)調(diào)用getpid可 以得到進(jìn)程的ID,而getppid可以得到父進(jìn)程(創(chuàng)建調(diào)用該函數(shù)進(jìn)程的進(jìn)程)的ID. #include ; pid_t getpid(void); pid_t getppid(void); 進(jìn)程是為程序服務(wù)的,而程序是為了用戶服務(wù)的.系統(tǒng)為了找到進(jìn)程的用戶名,還為進(jìn)程和 用戶建立聯(lián)系.這個(gè)用戶稱為進(jìn)程的所有者.相應(yīng)的每一個(gè)用戶也有一個(gè)用戶ID.通過(guò)系統(tǒng) 調(diào)用getuid可以得到進(jìn)程的所有者的ID.由于進(jìn)程要用到一些資源,而Linux對(duì)系統(tǒng)資源是 進(jìn)行保護(hù)的,

22、為了獲取一定資源進(jìn)程還有一個(gè)有效用戶ID.這個(gè)ID和系統(tǒng)的資源使用有關(guān) ,涉及到進(jìn)程的權(quán)限. 通過(guò)系統(tǒng)調(diào)用geteuid我們可以得到進(jìn)程的有效用戶ID. 和用戶ID 相對(duì)應(yīng)進(jìn)程還有一個(gè)組ID和有效組ID系統(tǒng)調(diào)用getgid和getegid可以分別得到組ID和有效 組ID #include ; #include ; uid_t getuid(void); uid_t geteuid(void); gid_t getgid(void); git_t getegid(void); 有時(shí)候我們還會(huì)對(duì)用戶的其他信息感興趣(登錄名等等),

23、這個(gè)時(shí)候我們可以調(diào)用getpwui d來(lái)得到. struct passwd { char *pw_name; /* 登錄名稱 */ char *pw_passwd; /* 登錄口令 */ uid_t pw_uid; /* 用戶ID */ gid_t pw_gid; /* 用戶組ID */ char *pw_gecos; /* 用戶的真名 */ char *pw_dir; /* 用戶的目錄 */ char *pw_shell; /* 用戶的SHELL */ }; #include ; #include ; struct pas

24、swd *getpwuid(uid_t uid); 下面我們學(xué)習(xí)一個(gè)實(shí)例來(lái)實(shí)踐一下上面我們所學(xué)習(xí)的幾個(gè)函數(shù): #include ; #include ; #include ; #include ; int main(int argc,char **argv) { pid_t my_pid,parent_pid; uid_t my_uid,my_euid; gid_t my_gid,my_egid; struct passwd *my_info; my_pid=getpid(); parent

25、_pid=getppid(); my_uid=getuid(); my_euid=geteuid(); my_gid=getgid(); my_egid=getegid(); my_info=getpwuid(my_uid); printf("Process ID:%ld\n",my_pid); printf("Parent ID:%ld\n",parent_pid); printf("User ID:%ld\n",my_uid); printf("Effective User ID:%ld\n",my_euid); printf("Group ID:%ld\n",my_g

26、id); printf("Effective Group ID:%ld\n",my_egid): if(my_info) { printf("My Login Name:%s\n" ,my_info->;pw_name); printf("My Password :%s\n" ,my_info->;pw_passwd); printf("My User ID :%ld\n",my_info->;pw_uid); printf("My Group ID :%ld\n",my_info->;pw_gid); printf("My Real Name:%s\n" ,my_info->

27、;pw_gecos); printf("My Home Dir :%s\n", my_info->;pw_dir); printf("My Work Shell:%s\n", my_info->;pw_shell); } } 3。進(jìn)程的創(chuàng)建 創(chuàng)建一個(gè)進(jìn)程的系統(tǒng)調(diào)用很簡(jiǎn)單.我們只要調(diào)用fork函數(shù)就可以了. #include ; pid_t fork(); 當(dāng)一個(gè)進(jìn)程調(diào)用了fork以后,系統(tǒng)會(huì)創(chuàng)建一個(gè)子進(jìn)程.這個(gè)子進(jìn)程和父進(jìn)程不同的地方只 有他的進(jìn)程ID和父進(jìn)程ID,其他的都是一樣.就象符進(jìn)程克隆(clone)自己一樣.當(dāng)然創(chuàng)建

28、兩個(gè)一模一樣的進(jìn)程是沒(méi)有意義的.為了區(qū)分父進(jìn)程和子進(jìn)程,我們必須跟蹤fork的返回 值. 當(dāng)fork掉用失敗的時(shí)候(內(nèi)存不足或者是用戶的最大進(jìn)程數(shù)已到)fork返回-1,否則f ork的返回值有重要的作用.對(duì)于父進(jìn)程fork返回子進(jìn)程的ID,而對(duì)于fork子進(jìn)程返回0.我 們就是根據(jù)這個(gè)返回值來(lái)區(qū)分父子進(jìn)程的. 父進(jìn)程為什么要?jiǎng)?chuàng)建子進(jìn)程呢?前面我們已經(jīng) 說(shuō)過(guò)了Linux是一個(gè)多用戶操作系統(tǒng),在同一時(shí)間會(huì)有許多的用戶在爭(zhēng)奪系統(tǒng)的資源.有時(shí) 進(jìn)程為了早一點(diǎn)完成任務(wù)就創(chuàng)建子進(jìn)程來(lái)爭(zhēng)奪資源. 一旦子進(jìn)程被創(chuàng)建,父子進(jìn)程一起從 fork處繼續(xù)執(zhí)行,相互競(jìng)爭(zhēng)系統(tǒng)的資源.有時(shí)候我們希望子進(jìn)程繼續(xù)

29、執(zhí)行,而父進(jìn)程阻塞直 到子進(jìn)程完成任務(wù).這個(gè)時(shí)候我們可以調(diào)用wait或者waitpid系統(tǒng)調(diào)用. #include ; #include ; pid_t wait(int *stat_loc); pid_t waitpid(pid_t pid,int *stat_loc,int options); wait系統(tǒng)調(diào)用會(huì)使父進(jìn)程阻塞直到一個(gè)子進(jìn)程結(jié)束或者是父進(jìn)程接受到了一個(gè)信號(hào).如果 沒(méi)有父進(jìn)程沒(méi)有子進(jìn)程或者他的子進(jìn)程已經(jīng)結(jié)束了wait回立即返回.成功時(shí)(因一個(gè)子進(jìn) 程結(jié)束)wait將返回子進(jìn)程的ID,否則返回-1,并設(shè)置全局變

30、量errno.stat_loc是子進(jìn)程的 退出狀態(tài).子進(jìn)程調(diào)用exit,_exit 或者是return來(lái)設(shè)置這個(gè)值. 為了得到這個(gè)值Linux定 義了幾個(gè)宏來(lái)測(cè)試這個(gè)返回值. WIFEXITED:判斷子進(jìn)程退出值是非0 WEXITSTATUS:判斷子進(jìn)程的退出值(當(dāng)子進(jìn)程退出時(shí)非0). WIFSIGNALED:子進(jìn)程由于有沒(méi)有獲得的信號(hào)而退出. WTERMSIG:子進(jìn)程沒(méi)有獲得的信號(hào)號(hào)(在WIFSIGNALED為真時(shí)才有意義). waitpid等待指定的子進(jìn)程直到子進(jìn)程返回.如果pid為正值則等待指定的進(jìn)程(pid).如果 為0則等待任何一個(gè)組ID和調(diào)用者的組ID相同的進(jìn)程.為

31、-1時(shí)等同于wait調(diào)用.小于-1時(shí)等 待任何一個(gè)組ID等于pid絕對(duì)值的進(jìn)程. stat_loc和wait的意義一樣. options可以決定 父進(jìn)程的狀態(tài).可以取兩個(gè)值 WNOHANG:父進(jìn)程立即返回當(dāng)沒(méi)有子進(jìn)程存在時(shí). WUNTACHE D:當(dāng)子進(jìn)程結(jié)束時(shí)waitpid返回,但是子進(jìn)程的退出狀態(tài)不可得到. 父進(jìn)程創(chuàng)建子進(jìn)程后,子進(jìn)程一般要執(zhí)行不同的程序.為了調(diào)用系統(tǒng)程序,我們可以使用系 統(tǒng)調(diào)用exec族調(diào)用.exec族調(diào)用有著5個(gè)函數(shù). #include ; int execl(const char *path,const char *arg,...);

32、 int execlp(const char *file,const char *arg,...); int execle(const char *path,const char *arg,...); int execv(const char *path,char *const argv[]); int execvp(const char *file,char *const argv[]): exec族調(diào)用可以執(zhí)行給定程序.關(guān)于exec族調(diào)用的詳細(xì)解說(shuō)可以參考系統(tǒng)手冊(cè)(man exec l). 下面我們來(lái)學(xué)習(xí)一個(gè)實(shí)例.注意編譯的時(shí)候要加 -lm以便連接數(shù)學(xué)函數(shù)庫(kù). #includ

33、e ; #include ; #include ; #include ; #include ; #include ; void main(void) { pid_t child; int status; printf("This will demostrate how to get child status\n"); if((child=fork())==-1) { printf("Fork Error :%s\n",strerror(errno)

34、); exit(1); } else if(child==0) { int i; printf("I am the child:%ld\n",getpid()); for(i=0;i<1000000;i++) sin(i); i=5; printf("I exit with %d\n",i); exit(i); } while(((child=wait(&status))==-1)&(errno==EINTR)); if(child==-1) printf("Wait Error:%s\n",strerror(errno)); else if(!status)

35、printf("Child %ld terminated normally return status is zero\n", child); else if(WIFEXITED(status)) printf("Child %ld terminated normally return status is %d\n", child,WEXITSTATUS(status)); else if(WIFSIGNALED(status)) printf("Child %ld terminated due to signal %d znot caught\n", child,WTERMSI

36、G(status)); } strerror函數(shù)會(huì)返回一個(gè)指定的錯(cuò)誤號(hào)的錯(cuò)誤信息的字符串. 4。守護(hù)進(jìn)程的創(chuàng)建 如果你在DOS時(shí)代編寫過(guò)程序,那么你也許知道在DOS下為了編寫一個(gè)常駐內(nèi)存的程序 我們要編寫多少代碼了.相反如果在Linux下編寫一個(gè)"常駐內(nèi)存"的程序卻是很容易的.我 們只要幾行代碼就可以做到. 實(shí)際上由于Linux是多任務(wù)操作系統(tǒng),我們就是不編寫代碼 也可以把一個(gè)程序放到后臺(tái)去執(zhí)行的.我們只要在命令后面加上&符號(hào)SHELL就會(huì)把我們的 程序放到后臺(tái)去運(yùn)行的. 這里我們"開(kāi)發(fā)"一個(gè)后臺(tái)檢查郵件的程序.這個(gè)程序每個(gè)一個(gè)指 定的時(shí)間回去檢查我們的

37、郵箱,如果發(fā)現(xiàn)我們有郵件了,會(huì)不斷的報(bào)警(通過(guò)機(jī)箱上的小喇 叭來(lái)發(fā)出聲音). 后面有這個(gè)函數(shù)的加強(qiáng)版本加強(qiáng)版本 后臺(tái)進(jìn)程的創(chuàng)建思想: 首先父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程.然后子進(jìn)程殺死父進(jìn)程(是不是很無(wú) 情?). 信號(hào)處理所有的工作由子進(jìn)程來(lái)處理. #include ; #include ; #include ; #include ; #include ; #include ; #include ; /* Linux 的默任個(gè)人的郵箱地址是

38、 /var/spool/mail/用戶的登錄名 */ #define MAIL "/var/spool/mail/hoyt" /* 睡眠10秒鐘 */ #define SLEEP_TIME 10 main(void) { pid_t child; if((child=fork())==-1) { printf("Fork Error:%s\n",strerror(errno)); exit(1); } else if(child>;0) while(1); if(kill(getppid(),SIGTERM)==-1) { printf("Kill Pare

39、nt Error:%s\n",strerror(errno)); exit(1); } { int mailfd; while(1) { if((mailfd=open(MAIL,O_RDONLY))!=-1) { fprintf(stderr,"%s","\007"); close(mailfd); } sleep(SLEEP_TIME); } } } 你可以在默認(rèn)的路徑下創(chuàng)建你的郵箱文件,然后測(cè)試一下這個(gè)程序.當(dāng)然這個(gè)程序還有很 多地方要改善的.我們后面會(huì)對(duì)這個(gè)小程序改善的,再看我的改善之前你可以嘗試自己改 善一下.比如讓用戶指定郵相的路徑和睡眠時(shí)間

40、等等.相信自己可以做到的.動(dòng)手吧,勇敢 的探險(xiǎn)者. 好了進(jìn)程一節(jié)的內(nèi)容我們就先學(xué)到這里了.進(jìn)程是一個(gè)非常重要的概念,許多的程序都會(huì) 用子進(jìn)程.創(chuàng)建一個(gè)子進(jìn)程是每一個(gè)程序員的基本要求! 3)Linux程序設(shè)計(jì)入門--文件操作 Linux下文件的操作 前言: 我們?cè)谶@一節(jié)將要討論linux下文件操作的各個(gè)函數(shù). 文件的創(chuàng)建和讀寫 文件的各個(gè)屬性 目錄文件的操作 管道文件 ---------------------------------------------------------------------------- ----

41、1。文件的創(chuàng)建和讀寫 我假設(shè)你已經(jīng)知道了標(biāo)準(zhǔn)級(jí)的文件操作的各個(gè)函數(shù)(fopen,fread,fwrite等等).當(dāng)然 如果你不清楚的話也不要著急.我們討論的系統(tǒng)級(jí)的文件操作實(shí)際上是為標(biāo)準(zhǔn)級(jí)文件操作 服務(wù)的. 當(dāng)我們需要打開(kāi)一個(gè)文件進(jìn)行讀寫操作的時(shí)候,我們可以使用系統(tǒng)調(diào)用函數(shù)open.使用完 成以后我們調(diào)用另外一個(gè)close函數(shù)進(jìn)行關(guān)閉操作. #include ; #include ; #include ; #include ; int open(const char *pat

42、hname,int flags); int open(const char *pathname,int flags,mode_t mode); int close(int fd); open函數(shù)有兩個(gè)形式.其中pathname是我們要打開(kāi)的文件名(包含路徑名稱,缺省是認(rèn)為在 當(dāng)前路徑下面).flags可以去下面的一個(gè)值或者是幾個(gè)值的組合. O_RDONLY:以只讀的方式打開(kāi)文件. O_WRONLY:以只寫的方式打開(kāi)文件. O_RDWR:以讀寫的方式打開(kāi)文件. O_APPEND:以追加的方式打開(kāi)文件. O_CREAT:創(chuàng)建一個(gè)文件. O_EXEC:如果使用了O_CREAT而且

43、文件已經(jīng)存在,就會(huì)發(fā)生一個(gè)錯(cuò)誤. O_NOBLOCK:以非阻塞的方式打開(kāi)一個(gè)文件. O_TRUNC:如果文件已經(jīng)存在,則刪除文件的內(nèi)容. 前面三個(gè)標(biāo)志只能使用任意的一個(gè).如果使用了O_CREATE標(biāo)志,那么我們要使用open的第 二種形式.還要指定mode標(biāo)志,用來(lái)表示文件的訪問(wèn)權(quán)限.mode可以是以下情況的組合. ----------------------------------------------------------------- S_IRUSR 用戶可以讀 S_IWUSR 用戶可以寫 S_IXUSR 用戶可以執(zhí)行 S_IRWXU 用戶可以讀寫執(zhí)行 -------

44、---------------------------------------------------------- S_IRGRP 組可以讀 S_IWGRP 組可以寫 S_IXGRP 組可以執(zhí)行 S_IRWXG 組可以讀寫執(zhí)行 ----------------------------------------------------------------- S_IROTH 其他人可以讀 S_IWOTH 其他人可以寫 S_IXOTH 其他人可以執(zhí)行 S_IRWXO 其他人可以讀寫執(zhí)行 -------------------------------------------------

45、---------------- S_ISUID 設(shè)置用戶執(zhí)行ID S_ISGID 設(shè)置組的執(zhí)行ID ----------------------------------------------------------------- 我們也可以用數(shù)字來(lái)代表各個(gè)位的標(biāo)志.Linux總共用5個(gè)數(shù)字來(lái)表示文件的各種權(quán)限. 00000.第一位表示設(shè)置用戶ID.第二位表示設(shè)置組ID,第三位表示用戶自己的權(quán)限位,第四 位表示組的權(quán)限,最后一位表示其他人的權(quán)限. 每個(gè)數(shù)字可以取1(執(zhí)行權(quán)限),2(寫權(quán)限),4(讀權(quán)限),0(什么也沒(méi)有)或者是這幾個(gè)值的和 .. 比如我們要?jiǎng)?chuàng)建一個(gè)用戶讀寫執(zhí)

46、行,組沒(méi)有權(quán)限,其他人讀執(zhí)行的文件.設(shè)置用戶ID位那么 我們可以使用的模式是--1(設(shè)置用戶ID)0(組沒(méi)有設(shè)置)7(1+2+4)0(沒(méi)有權(quán)限,使用缺省) 5(1+4)即10705: open("temp",O_CREAT,10705); 如果我們打開(kāi)文件成功,open會(huì)返回一個(gè)文件描述符.我們以后對(duì)文件的所有操作就可以 對(duì)這個(gè)文件描述符進(jìn)行操作了. 當(dāng)我們操作完成以后,我們要關(guān)閉文件了,只要調(diào)用close就可以了,其中fd是我們要關(guān)閉 的文件描述符. 文件打開(kāi)了以后,我們就要對(duì)文件進(jìn)行讀寫了.我們可以調(diào)用函數(shù)read和write進(jìn)行文件的 讀寫. #include

47、istd.h>; ssize_t read(int fd, void *buffer,size_t count); ssize_t write(int fd, const void *buffer,size_t count); fd是我們要進(jìn)行讀寫操作的文件描述符,buffer是我們要寫入文件內(nèi)容或讀出文件內(nèi)容的 內(nèi)存地址.count是我們要讀寫的字節(jié)數(shù). 對(duì)于普通的文件read從指定的文件(fd)中讀取count字節(jié)到buffer緩沖區(qū)中(記住我們必 須提供一個(gè)足夠大的緩沖區(qū)),同時(shí)返回count. 如果read讀到了文件的結(jié)尾或者被一個(gè)信號(hào)所中斷,返回值會(huì)小于count.如果

48、是由信號(hào)中 斷引起返回,而且沒(méi)有返回?cái)?shù)據(jù),read會(huì)返回-1,且設(shè)置errno為EINTR.當(dāng)程序讀到了文件 結(jié)尾的時(shí)候,read會(huì)返回0. write從buffer中寫count字節(jié)到文件fd中,成功時(shí)返回實(shí)際所寫的字節(jié)數(shù). 下面我們學(xué)習(xí)一個(gè)實(shí)例,這個(gè)實(shí)例用來(lái)拷貝文件. #include ; #include ; #include ; #include ; #include ; #include ; #include ; #d

49、efine BUFFER_SIZE 1024 int main(int argc,char **argv) { int from_fd,to_fd; int bytes_read,bytes_write; char buffer[BUFFER_SIZE]; char *ptr; if(argc!=3) { fprintf(stderr,"Usage:%s fromfile tofile\n\a",argv[0]); exit(1); } /* 打開(kāi)源文件 */ if((from_fd=open(argv[1],O_RDONLY))==-1) { fprintf(s

50、tderr,"Open %s Error:%s\n",argv[1],strerror(errno)); exit(1); } /* 創(chuàng)建目的文件 */ if((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1) { fprintf(stderr,"Open %s Error:%s\n",argv[2],strerror(errno)); exit(1); } /* 以下代碼是一個(gè)經(jīng)典的拷貝文件的代碼 */ while(bytes_read=read(from_fd,buffer,BUFFER_SIZE))

51、 { /* 一個(gè)致命的錯(cuò)誤發(fā)生了 */ if((bytes_read==-1)&&(errno!=EINTR)) break; else if(bytes_read>;0) { ptr=buffer; while(bytes_write=write(to_fd,ptr,bytes_read)) { /* 一個(gè)致命錯(cuò)誤發(fā)生了 */ if((bytes_write==-1)&&(errno!=EINTR))break; /* 寫完了所有讀的字節(jié) */ else if(bytes_write==bytes_read) break; /* 只寫了一部分,繼續(xù)寫 */ else

52、 if(bytes_write>;0) { ptr+=bytes_write; bytes_read-=bytes_write; } } /* 寫的時(shí)候發(fā)生的致命錯(cuò)誤 */ if(bytes_write==-1)break; } } close(from_fd); close(to_fd); exit(0); } 2。文件的各個(gè)屬性 文件具有各種各樣的屬性,除了我們上面所知道的文件權(quán)限以外,文件還有創(chuàng)建時(shí)間 ,大小等等屬性. 有時(shí)侯我們要判斷文件是否可以進(jìn)行某種操作(讀,寫等等).這個(gè)時(shí)候我們可以使用acce ss函數(shù). #includ

53、e ; int access(const char *pathname,int mode); pathname:是文件名稱,mode是我們要判斷的屬性.可以取以下值或者是他們的組合. R_OK文件可以讀,W_OK文件可以寫,X_OK文件可以執(zhí)行,F_OK文件存在.當(dāng)我們測(cè)試成功時(shí) ,函數(shù)返回0,否則如果有一個(gè)條件不符時(shí),返回-1. 如果我們要獲得文件的其他屬性,我們可以使用函數(shù)stat或者fstat. #include ; #include ; int stat(const char *file_name,st

54、ruct stat *buf); int fstat(int filedes,struct stat *buf); struct stat { dev_t st_dev; /* 設(shè)備 */ ino_t st_ino; /* 節(jié)點(diǎn) */ mode_t st_mode; /* 模式 */ nlink_t st_nlink; /* 硬連接 */ uid_t st_uid; /* 用戶ID */ gid_t st_gid; /* 組ID */ dev_t st_rdev; /* 設(shè)備類型 */ off_t st_off; /* 文件字節(jié)數(shù) */ unsigned long st

55、_blksize; /* 塊大小 */ unsigned long st_blocks; /* 塊數(shù) */ time_t st_atime; /* 最后一次訪問(wèn)時(shí)間 */ time_t st_mtime; /* 最后一次修改時(shí)間 */ time_t st_ctime; /* 最后一次改變時(shí)間(指屬性) */ }; stat用來(lái)判斷沒(méi)有打開(kāi)的文件,而fstat用來(lái)判斷打開(kāi)的文件.我們使用最多的屬性是st_ mode.通過(guò)著屬性我們可以判斷給定的文件是一個(gè)普通文件還是一個(gè)目錄,連接等等.可以 使用下面幾個(gè)宏來(lái)判斷. S_ISLNK(st_mode):是否是一個(gè)連接.S_ISREG

56、是否是一個(gè)常規(guī)文件.S_ISDIR是否是一個(gè)目 錄S_ISCHR是否是一個(gè)字符設(shè)備.S_ISBLK是否是一個(gè)塊設(shè)備S_ISFIFO是否 是一個(gè)FIFO文 件.S_ISSOCK是否是一個(gè)SOCKET文件. 我們會(huì)在下面說(shuō)明如何使用這幾個(gè)宏的. 3。目錄文件的操作 在我們編寫程序的時(shí)候,有時(shí)候會(huì)要得到我們當(dāng)前的工作路徑。C庫(kù)函數(shù)提供了get cwd來(lái)解決這個(gè)問(wèn)題。 #include ; char *getcwd(char *buffer,size_t size); 我們提供一個(gè)size大小的buffer,getcwd會(huì)把我們當(dāng)前的路徑考到

57、buffer中.如果buffer 太小,函數(shù)會(huì)返回-1和一個(gè)錯(cuò)誤號(hào). Linux提供了大量的目錄操作函數(shù),我們學(xué)習(xí)幾個(gè)比較簡(jiǎn)單和常用的函數(shù). #include ; #include ; #include ; #include ; #include ; int mkdir(const char *path,mode_t mode); DIR *opendir(const char *path); struct dirent *readdir(DIR *dir); vo

58、id rewinddir(DIR *dir); off_t telldir(DIR *dir); void seekdir(DIR *dir,off_t off); int closedir(DIR *dir); struct dirent { long d_ino; off_t d_off; unsigned short d_reclen; char d_name[NAME_MAX+1]; /* 文件名稱 */ mkdir很容易就是我們創(chuàng)建一個(gè)目錄,opendir打開(kāi)一個(gè)目錄為以后讀做準(zhǔn)備.readdir讀一 個(gè)打開(kāi)的目錄.rewinddir是用來(lái)重讀目錄的和我們學(xué)的re

59、wind函數(shù)一樣.closedir是關(guān)閉 一個(gè)目錄.telldir和seekdir類似與ftee和fseek函數(shù). 下面我們開(kāi)發(fā)一個(gè)小程序,這個(gè)程序有一個(gè)參數(shù).如果這個(gè)參數(shù)是一個(gè)文件名,我們輸出這 個(gè)文件的大小和最后修改的時(shí)間,如果是一個(gè)目錄我們輸出這個(gè)目錄下所有文件的大小和 修改時(shí)間. #include ; #include ; #include ; #include ; #include ; #include ; #include

60、h>; static int get_file_size_time(const char *filename) { struct stat statbuf; if(stat(filename,&statbuf)==-1) { printf("Get stat on %s Error:%s\n", filename,strerror(errno)); return(-1); } if(S_ISDIR(statbuf.st_mode))return(1); if(S_ISREG(statbuf.st_mode)) printf("%s size:%ld bytes\tmod

61、ified at %s", filename,statbuf.st_size,ctime(&statbuf.st_mtime)); return(0); } int main(int argc,char **argv) { DIR *dirp; struct dirent *direntp; int stats; if(argc!=2) { printf("Usage:%s filename\n\a",argv[0]); exit(1); } if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))ex

62、it(1); if((dirp=opendir(argv[1]))==NULL) { printf("Open Directory %s Error:%s\n", argv[1],strerror(errno)); exit(1); } while((direntp=readdir(dirp))!=NULL) if(get_file_size_time(direntp-

63、供了< >; | <<等等重定向操作符.在這些過(guò)濾和重 定向程序當(dāng)中,都用到了管 道這種特殊的文件.系統(tǒng)調(diào)用pipe可以創(chuàng)建一個(gè)管道. #include; int pipe(int fildes[2]); pipe調(diào)用可以創(chuàng)建一個(gè)管道(通信緩沖區(qū)).當(dāng)調(diào)用成功時(shí),我們可以訪問(wèn)文件描述符fild es[0],fildes[1].其中fildes[0]是用來(lái)讀的文件描述符,而fildes[1]是用來(lái)寫的文件描 述符. 在實(shí)際使用中我們是通過(guò)創(chuàng)建一個(gè)子進(jìn)程,然后一個(gè)進(jìn)程寫,一個(gè)進(jìn)程讀來(lái)使用的. 關(guān)于進(jìn)程通信的詳細(xì)情況請(qǐng)查看進(jìn)程通信 #include

64、io.h>; #include ; #include ; #include ; #include ; #include ; #include ; #define BUFFER 255 int main(int argc,char **argv) { char buffer[BUFFER+1]; int fd[2]; if(argc!=2) { fprintf(stderr,"Usage:%s string\n\a",argv[0]); e

65、xit(1); } if(pipe(fd)!=0) { fprintf(stderr,"Pipe Error:%s\n\a",strerror(errno)); exit(1); } if(fork()==0) { close(fd[0]); printf("Child[%d] Write to pipe\n\a",getpid()); snprintf(buffer,BUFFER,"%s",argv[1]); write(fd[1],buffer,strlen(buffer)); printf("Child[%d] Quit\n\a",getpid()); exi

66、t(0); } else { close(fd[1]); printf("Parent[%d] Read from pipe\n\a",getpid()); memset(buffer,\0,BUFFER+1); read(fd[0],buffer,BUFFER); printf("Parent[%d] Read:%s\n",getpid(),buffer); exit(1); } } 為了實(shí)現(xiàn)重定向操作,我們需要調(diào)用另外一個(gè)函數(shù)dup2. #include ; int dup2(int oldfd,int newfd); dup2將用oldfd文件描述符來(lái)代替newfd文件描述符,同時(shí)關(guān)閉newfd文件描述符.也就是說(shuō) , 所有向newfd操作都轉(zhuǎn)到oldfd上面.下面我們學(xué)習(xí)一個(gè)例子,這個(gè)例子將標(biāo)準(zhǔn)輸出重定向 到一個(gè)文件. #include ; #include ; #include ; #include ; #includ

展開(kāi)閱讀全文
溫馨提示:
1: 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
5. 裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

相關(guān)資源

更多
正為您匹配相似的精品文檔
關(guān)于我們 - 網(wǎng)站聲明 - 網(wǎng)站地圖 - 資源地圖 - 友情鏈接 - 網(wǎng)站客服 - 聯(lián)系我們

copyright@ 2023-2025  zhuangpeitu.com 裝配圖網(wǎng)版權(quán)所有   聯(lián)系電話:18123376007

備案號(hào):ICP2024067431號(hào)-1 川公網(wǎng)安備51140202000466號(hào)


本站為文檔C2C交易模式,即用戶上傳的文檔直接被用戶下載,本站只是中間服務(wù)平臺(tái),本站所有文檔下載所得的收益歸上傳人(含作者)所有。裝配圖網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)上載內(nèi)容本身不做任何修改或編輯。若文檔所含內(nèi)容侵犯了您的版權(quán)或隱私,請(qǐng)立即通知裝配圖網(wǎng),我們立即給予刪除!