版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、linux 操作系統(tǒng)下 c 語言編程入門unix 操作系統(tǒng)下同樣適用linux 操作系統(tǒng)下 c 語言編程入門整理編寫:007xio ng原文:Hoyt 等(一) 目錄介紹1) Linux 程序設(shè)計(jì)入門-基礎(chǔ)知識2) Linux 程序設(shè)計(jì)入門-進(jìn)程介紹3) Linux 程序設(shè)計(jì)入門-文件操作4) Linux 程序設(shè)計(jì)入門-時(shí)間概念5) Linux 程序設(shè)計(jì)入門-信號處理6) Linux 程序設(shè)計(jì)入門-消息管理7) Linux 程序設(shè)計(jì)入門-線程操作8) Linux 程序設(shè)計(jì)入門-網(wǎng)絡(luò)編程9) Linux 下 C 開發(fā)工具介紹(二) 具體內(nèi)容1)Linux 程序設(shè)計(jì)入門-基礎(chǔ)知識Linux 下 C
2、 語言編程基礎(chǔ)知識、八 、-刖言:這篇文章介紹在 LINUX 下進(jìn)行 C 語言編程所需要的基礎(chǔ)知識在這篇文章當(dāng)中,我 們將會學(xué)到以下內(nèi)容:源程序編譯Makefile 的編寫程序庫的鏈接程序的調(diào)試頭文件和系統(tǒng)求助1源程序的編譯在 Linux 下面,如果要編譯一個(gè) C 語言源程序,我們要使用 GNU 的 gcc 編譯器.下 面我們以一個(gè)實(shí)例來說明如何使用 gcc 編譯器.假設(shè)我們有下面一個(gè)非常簡單的源程序(hello.c):int main (i nt argc,char *argv)prin tf(Hello Linu xn);要編譯這個(gè)程序,我們只要在命令行下執(zhí)行:gcc -o hello h
3、ello.cgcc 編譯器就會為我們生成一個(gè) hello 的可執(zhí)行文件.執(zhí)行./hello 就可以看到程序的 輸出結(jié)果了 命令行中 gcc 表示我們是用 gcc 來編譯我們的源程序,-o 選項(xiàng)表示我 們要求編譯 器給我們輸出的可執(zhí)行文件名為 hello 而 hello.c 是我們的源程序文件. gcc 編譯器有許多選項(xiàng),一般來說我們只要知道其中的幾個(gè)就夠了. -o 選項(xiàng)我們已經(jīng)知道了,表示我們要求輸出的可執(zhí)行文件名 -c 選項(xiàng)表示我們只要求編譯器輸出目 標(biāo)代碼,而不必要輸出可執(zhí)行文件.-g 選項(xiàng)表示我們要求編譯器在編譯的時(shí)候提供 我們以后對程序進(jìn)行調(diào)試的信息.知道了這三個(gè)選項(xiàng),我們就可以編譯我
4、們自己所寫的簡單的源程序了,如果你想要知道更多的選項(xiàng),可以查看 gcc 的幫助文檔,那里有著許多對其它選項(xiàng)的詳細(xì)說明.2.Makefile 的編寫假設(shè)我們有下面這樣的一個(gè)程序,源代碼如下:/* mai n.c */#i nclude mytooll.h#i nclude mytool2.hint main (i nt argc,char *argv)mytool1_pri nt(hello);mytool2_pri nt(hello);/* mytooll.h */#ifndef _MYTOOL_1_H#defi ne _MYTOOL_1_Hvoid mytool1_pri nt(char *
5、pri nt_str);#en dif/* mytooll.c */#i nclude mytooll.hvoid mytool1_pri nt(char *pri nt_str)prin tf(This is mytooll print %sn ,pri nt_str);/* mytool2.h */#ifndef _MYT00L_2_H#defi ne _MYT00L_2_Hvoid mytool2_pri nt(char *pri nt_str);#en dif/* mytool2.c */#i nclude mytool2.hvoid mytool2_pri nt(char *pri
6、nt_str)prin tf(This is mytool2 print %sn ,pri nt_str);當(dāng)然由于這個(gè)程序是很短的我們可以這樣來編譯gcc -c mai n.cgcc -c mytooll.cgcc -c mytool2.cgcc -o ma in mai n.o mytooll.o mytool2.o這樣的話我們也可以產(chǎn)生 main 程序,而且也不時(shí)很麻煩.但是如果我們考慮一下如 果有一天我們修改了其中的一個(gè)文件(比如說 mytooll.c)那么我們難道還要重新輸 入上面的命令?也許你會說,這個(gè)很容易解決啊,我寫一個(gè) SHELL 腳本,讓她幫我去 完成不就可以了 是的對于這
7、個(gè)程序來說,是可以起到作用的但是當(dāng)我們把事情想 的更復(fù)雜一點(diǎn),如果我們的程 序有幾百個(gè)源程序的時(shí)候,難道也要編譯器重新一個(gè) 一個(gè)的去編譯?為此,聰明的程序員們想出了一個(gè)很好的工具來做這件事情,這就是 make.我們只要執(zhí)行以下 make 就可以把上面的問題解決掉.在我們執(zhí)行 make 之前,我們要先編寫 一個(gè)非常重要的 文件.-Makefile.對于上面的那個(gè)程序來說,可能的一個(gè) Makefile 的 文件是:#這是上面那個(gè)程序的 Makefile 文件mai n: mai n.o mytooll.o mytool2.ogcc -o ma in mai n.o mytooll.o mytool
8、2.omai n. o:mai n.c mytooll.h mytool2.hgcc -c mai n.cmytool1.o:mytool1.c mytooll.hgcc -c mytooll.cmytool2.o:mytool2.c mytool2.hgcc -c mytool2.c有了這個(gè) Makefile 文件,不過我們什么時(shí)候修改了源程序當(dāng)中的什么文件,我們只要執(zhí)行 make 命令,我們的編譯器都只會去編譯和我們修改的文件有關(guān)的文件,其它 的文件她連理都不想去理的.下面我們學(xué)習(xí) Makefile 是如何編寫的.在 Makefile中也#開始的行都是注釋行.Makefile中最重要的是描
9、述文件的依賴關(guān) 系的說明.一般的格式是:target: comp onentsTAB rule第一行表示的是依賴關(guān)系.第二行是規(guī)則.比如說我們上面的那個(gè) Makefile 文件的第二行mai n: mai n.o mytool1.o mytool2.o表示我們的目標(biāo)(target)ma in 的依賴對象(comp onen ts)是 ma in .o mytool1.omytool2.o 當(dāng)倚賴的對象在目標(biāo)修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我 們的上 面那個(gè) Makefile 第三行所說的一樣要執(zhí)行 gcc -o main main.o mytool1.omytool2.o
10、注意規(guī)則一行中的 TAB 表示那里是一個(gè) TAB 鍵Makefile 有三個(gè)非常有用的變量.分別是$,$,$八八,$,$代表的意義分別是:$-$-目標(biāo)文件, $ $八八-所有的依賴文件,$,$第一個(gè)依賴文件. .如果我們使用上面三個(gè)變量,那么我們可以簡化我們的 Makefile 文件為:#這是簡化后的 Makefilemai n: mai n.o mytooll.o mytool2.ogcc -o $ $Amai n. o:mai n.c mytooll.h mytool2.hgcc -c $mytool1.o:mytool1.c mytooll.hgcc -c $mytool2.o:myto
11、ol2.c mytool2.hgcc -c $經(jīng)過簡化后我們的 Makefile 是簡單了一點(diǎn),不過人們有時(shí)候還想簡單一點(diǎn).這里我 們學(xué)習(xí)一個(gè) Makefile 的缺省規(guī)則.c.o:gcc -c $這個(gè)規(guī)則表示所有的.o 文件都是依賴與相應(yīng)的.c 文件的.例如 mytool.o 依賴于mytool.c 這樣 Makefile 還可以變?yōu)椋?這是再一次簡化后的 Makefilemai n: mai n.o mytooll.o mytool2.ogcc -o $ $A.c.o:gcc -c $好了,我們的 Makefile 也差不多了,如果想知道更多的關(guān)于 Makefile 規(guī)則可以查看 相應(yīng)的文
12、檔3程序庫的鏈接試著編譯下面這個(gè)程序/* temp.c */#in clude int main (i nt argc,char *argv)double value;prin tf(Value:%fn,value);這個(gè)程序相當(dāng)簡單,但是當(dāng)我們用 gcc -o temp temp.c 編譯時(shí)會出現(xiàn)下面所示的錯(cuò)誤./tmp/cc33Kydu.o: In fun ctio n mai n:/tmp/cc33Kydu.o(.text+0 xe): un defi ned refere nee to logcollect2: ld returned 1 exit status出現(xiàn)這個(gè)錯(cuò)誤是因?yàn)榫幾g器
13、找不到log的具體實(shí)現(xiàn).雖然我們包括了正確的頭文件 但是我們在編譯的時(shí)候還是要連接確定的庫.在 Linux 下,為了使用數(shù)學(xué)函數(shù),我們 必須和數(shù)學(xué)庫 連接,為此我們要加入-lm 選項(xiàng).gcc -o temp temp.c -lm 這樣才能夠 正確的編譯.也許有人要問,前面我們用 printf 函數(shù)的時(shí)候怎么沒有連接庫呢?是這 樣的,對于一些常用的函 數(shù)的實(shí)現(xiàn),gcc 編譯器會自動去連接一些常用庫,這樣我們 就沒有必要自己去指定了 .有時(shí)候我們在編譯程序的時(shí)候還要指定庫的路徑,這個(gè) 時(shí)候我們要用到編譯器的-L 選項(xiàng)指定路徑.比如說我們有一個(gè)庫在/home/hoyt/mylib 下,這樣我們編譯的
14、時(shí)候還要加上 -L/h ome/hoyt/mylib.對于一些 標(biāo)準(zhǔn)庫來說,我們沒有必要指出路徑.只要它們在起缺省庫的路徑下就可以了 .系統(tǒng) 的缺省庫的路徑/lib /usr/lib /usr/local/lib 在這三個(gè)路徑下面 的庫,我們可以不指定 路徑.還有一個(gè)問題,有時(shí)候我們使用了某個(gè)函數(shù),但是我們不知道庫的名字,這個(gè)時(shí)候怎 么辦呢?很抱歉,對于這個(gè)問題我也不知道答案,我只有一個(gè)傻辦法.首先,我到標(biāo)準(zhǔn) 庫路徑下面去找看看有沒有和我用的函數(shù)相關(guān)的庫,我就這樣找到了線程(thread) 函數(shù)的庫文件(libpthread.a).當(dāng)然,如果找不到,只有一個(gè)笨方法.比如我要找 sin 這個(gè)函數(shù)
15、所在的庫.就 只好用 nm -o /lib/*so|grep sin/sin 命令撚后看/sin 文件,到那里面去找了 .在 s in 文件當(dāng)中,我會找到這樣的一行 Iibm-2.1.2.so:00009fa0 W sin 這樣我就知道了 sin 在libm-2.1.2.so 庫里面,我用-lm 選項(xiàng)就可以了(去掉前面的 lib 和后面的版本標(biāo)志,就剩下 m 了所以是-lm).如果你知道怎么找,請趕快告訴我,我回非常感激的.謝謝!4. 程序的調(diào)試我們編寫的程序不太可能一次性就會成功的,在我們的程序當(dāng)中,會出現(xiàn)許許多多 我們想不到的錯(cuò)誤,這個(gè)時(shí)候我們就要對我們的程序進(jìn)行調(diào)試了.最常用的調(diào)試軟件是
16、 gdb.如果你想在圖形界面下調(diào)試程序,那么你現(xiàn)在可以選擇 xxgdb.記得要在編譯的時(shí)候加入-g 選項(xiàng).關(guān)于 gdb 的使用可以看 gdb 的幫助文件. 由于我沒有用過這個(gè)軟件,所以我也不能夠說出如何使用.不過我不喜歡用 gdb.跟 蹤一個(gè)程序是很煩的事情,我一般用在程序當(dāng)中輸出中間變量的值來調(diào)試程序的.當(dāng)然你可以選擇自己的辦法,沒有必要去學(xué)別人的.現(xiàn)在有了許多 IDE 環(huán)境,里面已 經(jīng)自己帶了調(diào)試器了 .你可以選擇幾個(gè)試 一試找出自己喜歡的一個(gè)用.5. 頭文件和系統(tǒng)求助有時(shí)候我們只知道一個(gè)函數(shù)的大概形式,不記得確切的表達(dá)式,或者是不記得著函 數(shù)在那個(gè)頭文件進(jìn)行了說明.這個(gè)時(shí)候我們可以求助系
17、統(tǒng).比如說我們想知道 fread 這個(gè)函數(shù)的確切形式,我們只要執(zhí)行 man fread 系統(tǒng)就會輸 出著函數(shù)的詳細(xì)解釋的.和這個(gè)函數(shù)所在的頭文件stdio.h說明了 .如果我們要 write 這個(gè)函數(shù)的說明,當(dāng)我們執(zhí)行 man write 時(shí),輸出的結(jié)果卻不是我們所需要的. 因?yàn)槲覀円氖?w rite 這個(gè)函數(shù)的說明,可是出來的卻是 write 這個(gè)命令的說明.為 了得到 write 的函數(shù)說明 我們要用 man 2 write. 2 表示我們用的 write 這個(gè)函數(shù)是 系統(tǒng)調(diào)用函數(shù),還有一個(gè)我們常 用的是 3 表示函數(shù)是 C 的庫函數(shù).記住不管什么時(shí)候,man 都是我們的最好助手.好了,
18、這一章就講這么多了,有了這些知識我們就可以進(jìn)入激動人心的Linux 下的 C程序探險(xiǎn)活動.2)Linux 程序設(shè)計(jì)入門-進(jìn)程介紹Linux 下進(jìn)程的創(chuàng)建、八 、-刖言:這篇文章是用來介紹在 Linux 下和進(jìn)程相關(guān)的各個(gè)概念.我們將會學(xué)到:進(jìn)程的概念進(jìn)程的身份 進(jìn)程的創(chuàng)建 守護(hù)進(jìn)程的創(chuàng)建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è)開始執(zhí)行但是還沒有結(jié)束的程
19、 序的實(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)用到內(nèi)存以后,系統(tǒng)會給程序分配一定的資 源(內(nèi)存,設(shè)備等等)然后進(jìn)行一系列的復(fù)雜操作,使程序變成進(jìn)程以供系統(tǒng)調(diào)用在 系統(tǒng)里面只 有進(jìn)程沒有程序,為了區(qū)分各個(gè)不同的進(jìn)程,系統(tǒng)給每一個(gè)進(jìn)程分配了 一個(gè)ID(就象我們的 身份證)以便識別為了充分的利用資源,系統(tǒng)還對進(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 來執(zhí)行命令,而完成
20、表示進(jìn)程已經(jīng)結(jié)束了系統(tǒng)正在回收資源.關(guān) 于進(jìn)程五個(gè)狀態(tài)的詳細(xì)解說我們可以看操作系統(tǒng)上面有詳細(xì)的解說。2。 進(jìn)程的標(biāo)志上面我們知道了進(jìn)程都有一個(gè)ID,那么我們怎么得到進(jìn)程的ID呢?系統(tǒng)調(diào)用getpid 可以得到進(jìn)程的 ID,而 getppid 可以得到父進(jìn)程(創(chuàng)建調(diào)用該函數(shù)進(jìn)程的進(jìn)程)的 ID.#in elude 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.通過系統(tǒng) 調(diào)用 getuid 可以得到進(jìn)程的所有者
21、的 ID.由于進(jìn)程要用到一些資源, 而 Linux 對系統(tǒng)資源是 進(jìn)行保護(hù)的,為了獲取一定資源進(jìn)程還有一個(gè)有效用戶ID.這個(gè) ID 和系統(tǒng)的資源使用有關(guān),涉及到進(jìn)程的權(quán)限.通過系統(tǒng)調(diào)用 geteuid 我們可 以得到進(jìn)程的有效用戶 ID.和用戶 ID 相對應(yīng)進(jìn)程還有一個(gè)組 ID 和有效組 ID 系統(tǒng)調(diào)用 getgid和 getegid 可以分別得到組 ID 和有效組 ID#in elude #i nclude uid_t getuid(void); uid_t geteuid(void);gid_t getgid(void);git_t getegid(void);有時(shí)候我們還會對用戶的其他信
22、息感興趣(登錄名等等),這個(gè)時(shí)候我們可以調(diào)用 getpwuid 來得到.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 */ ;#in clude #i nclude struct passwd *getpwuid(uid_t uid);下面
23、我們學(xué)習(xí)一個(gè)實(shí)例來實(shí)踐一下上面我們所學(xué)習(xí)的幾個(gè)函數(shù):#i nclude #in clude #i nclude #i nclude int main (i nt argc,char *argv)pid_t my_pid,pare nt_pid;uid_t my_uid,my_euid; gid_t my_gid,my_egid;struct passwd *my_i nfo;my_pid=getpid();pare nt_pid=getppid(); my_uid=getuid(); my_euid=geteuid();my_gid=getgid(); my_egid=getegid();my
24、_i nfo=getpwuid(my_uid);prin tf(Process ID:%ldn,my_pid);printf(Parent ID:%ldn,parent_pid);prin tf(User ID:%ldn,my_uid);prin tf(Effective User ID:%ldn,my_euid);prin tf(Group ID:%ldn,my_gid);prin tf(Effective Group ID:%ldn,my_egid):if(my_i nfo)prin tf(My Log in Name:%sn ,my_i nfo-pw_ name);prin tf(My
25、Password :%sn ,my_i nfo-pw_passwd);prin tf(My User ID :%ldn,my_i nfo-pw_uid);prin tf(My Group ID :%ldn,my_i nfo-pw_gid);prin tf(My Real Name:%sn ,my_i nfo-pw_gecos);prin tf(My Home Dir :%sn, my_i nfo-pw_dir);prin tf(My Work Shell:%sn, my_i nfo-pw_shell);3。進(jìn)程的創(chuàng)建創(chuàng)建一個(gè)進(jìn)程的系統(tǒng)調(diào)用很簡單.我們只要調(diào)用 fork 函數(shù)就可以了 .#i n
26、clude pid_t fork();當(dāng)一個(gè)進(jìn)程調(diào)用了 fork 以后,系統(tǒng)會創(chuàng)建一個(gè)子進(jìn)程.這個(gè)子進(jìn)程和父進(jìn)程不同的 地方只有他的進(jìn)程 ID 和父進(jìn)程 ID,其他的都是一樣.就象符進(jìn)程克隆(clone)自己 一樣.當(dāng)然創(chuàng)建 兩個(gè)一模一樣的進(jìn)程是沒有意義的為了區(qū)分父進(jìn)程和子進(jìn)程,我們 必須跟蹤 fork的返回值.當(dāng) fork 掉用失敗的時(shí)候(內(nèi)存不足或者是用戶的最大進(jìn)程 數(shù)已到)fork 返回-1,否則 f ork 的返回值有重要的作用.對于父進(jìn)程 fork 返回子進(jìn)程 的 ID,而對于 fork 子進(jìn)程返回 0.我們就是根據(jù)這個(gè)返回值來區(qū)分父子進(jìn)程的.父進(jìn)程為什么要創(chuàng)建子進(jìn)程呢?前面我 們已
27、經(jīng)說過了 Linux 是一個(gè)多用戶操作系統(tǒng),在同一時(shí)間會有許多的用戶在爭奪系 統(tǒng)的資源有時(shí)進(jìn)程為了早一點(diǎn)完成任務(wù)就創(chuàng)建子進(jìn)程來爭奪資源一旦子進(jìn)程被創(chuàng)建,父子進(jìn)程一起從fork處繼續(xù)執(zhí)行,相互競爭系統(tǒng)的資源.有時(shí)候我們希望子進(jìn) 程繼續(xù)執(zhí)行,而父進(jìn)程阻塞直到子進(jìn)程完成任務(wù)這個(gè)時(shí)候我們可以調(diào)用 wait 或者 waitpid 系統(tǒng)調(diào)用.#i nclude #i nclude pid_t wait(i nt *stat_loc);pid_t waitpid(pid_t pid,i nt *stat_loc,i nt opti on s);wait 系統(tǒng)調(diào)用會使父進(jìn)程阻塞直到一個(gè)子進(jìn)程結(jié)束或者是父進(jìn)程接
28、受到了一個(gè)信 號.如果沒有父進(jìn)程沒有子進(jìn)程或者他的子進(jìn)程已經(jīng)結(jié)束了wait 回立即返回.成功時(shí)(因一個(gè)子進(jìn) 程結(jié)束)wait 將返回子進(jìn)程的 ID,否則返回-1,并設(shè)置全局變量errno.stat_loc 是子進(jìn)程的退出狀態(tài).子進(jìn)程調(diào)用 exit,_exit 或者是 return 來設(shè)置這個(gè) 值.為了得到這個(gè)值 Linux 定義了幾個(gè)宏來測試這個(gè)返回值.WIFEXITED:判斷子進(jìn)程退出值是非 0WEXITSTATUS:判斷子進(jìn)程的退出值(當(dāng)子進(jìn)程退出時(shí)非 0).WIFSIGNALED:子進(jìn)程由于有沒有獲得的信號而退出.WTERMSIG:子進(jìn)程沒有獲得的信號號(在 WIFSIGNALED 為真
29、時(shí)才有意義). waitpid 等待指定的子進(jìn)程直到子進(jìn)程返回.如果 pid 為正值則等待指定的進(jìn)程(pid). 如果為 0 則等待任何一個(gè)組 ID 和調(diào)用者的組 ID 相同的進(jìn)程.為-1 時(shí)等同于 wait 調(diào)用. 小于-1時(shí)等 待任何一個(gè)組 ID 等于 pid 絕對值的進(jìn)程.stat_loc 和 wait 的意義一樣. opti ons 可以決定父進(jìn)程的狀態(tài).可以取兩個(gè)值 WNOHANG:父進(jìn)程立即返回當(dāng)沒有子進(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)程序,我們可以 使
30、用系 統(tǒng)調(diào)用 exec 族調(diào)用.exec 族調(diào)用有著 5 個(gè)函數(shù).#i nclude int execl(c onst char *path,c onst char *arg,.);int execlp(c onst char *file,c onst char *arg,.);int execle(c onst char *path,c onst char *arg,.);int execv(c onst char *path,char *const argv);int execvp(c onst char *file,char *const argv):exec 族調(diào)用可以執(zhí)行給定程序.關(guān)
31、于 exec 族調(diào)用的詳細(xì)解說可以參考系統(tǒng)手冊 (manexec l).下面我們來學(xué)習(xí)一個(gè)實(shí)例.注意編譯的時(shí)候要加-Im 以便連接數(shù)學(xué)函 數(shù)庫.#i nclude #i nclude #i nclude #i nclude #i nclude #in clude void ma in (void)pid_t child;int status;printf(This will demostrate how to get child statusn);if(child=fork()=-1)prin tf(Fork Error :%sn,strerror(errino);exit(1);else i
32、f(child=0)int i;prin tf(I am the child:%ldn,getpid();for(i=0;i1000000;i+) sin(i);i=5;prin tf(I exit with %dn,i);exit(i);while(child=wait(& status)=-1)&(errno=EINTR);if(child=-1)prin tf(Wait Error:%sn,strerror(err no);else if(!status)printf(Child %ld terminated normally return status is zeron
33、,child);else if(WIFEXITED(status)printf(Child %ld terminated normally return status is %dn,child,WEXITSTATUS(status);else if(WIFSIGNALED(status)prin tf(Child %ld term in ated due to sig nal %d znot caughtn,child,WTERMSIG(status);strerror 函數(shù)會返回一個(gè)指定的錯(cuò)誤號的錯(cuò)誤信息的字符串4。守護(hù)進(jìn)程的創(chuàng)建如果你在 DOS 時(shí)代編寫過程序,那么你也許知道在 DOS 下
34、為了編寫一個(gè)常駐內(nèi)存 的程序我們要編寫多少代碼了 相反如果在 Linux 下編寫一個(gè)常駐內(nèi)存的程序卻 是很容易的.我們只要幾行代碼就可以做到實(shí)際上由于 Linux 是多任務(wù)操作系統(tǒng), 我們就是不編寫代碼也可以把一個(gè)程序放到后臺去執(zhí)行的我們只要在命令后面 加上&符號 SHELL 就會把我們的 程序放到后臺去運(yùn)行的.這里我們開發(fā)一個(gè)后 臺檢查郵件的程序.這個(gè)程序每個(gè)一個(gè)指 定的時(shí)間回去檢查我們的郵箱,如果發(fā)現(xiàn) 我們有郵件了,會不斷的報(bào)警(通過機(jī)箱上的小喇叭來發(fā)出聲音).后面有這個(gè)函數(shù) 的加強(qiáng)版本加強(qiáng)版本后臺進(jìn)程的創(chuàng)建思想:首先父進(jìn)程創(chuàng)建一個(gè)子進(jìn)程.然后子進(jìn)程殺死父進(jìn)程(是不是 很無情?).
35、信號處理所有的工作由子進(jìn)程來處理.#i nclude #i nclude #i nclude #i nclude #i nclude verrno .h#in clude #in clude /* Linux 的默任個(gè)人的郵箱地址是/var/spool/mail/用戶的登錄名*/#define MAIL /var/spool/mail/hoyt/*睡眠 10 秒鐘*/#defi ne SLEEP_TIME 10mai n(void)pid_t child;if(child=fork()=-1)prin tf(Fork Error:%sn,strerror(err no);exit(1);els
36、e if(child0)while(1);if(kill(getppid(),SIGTERM)=-1)prin tf(Kill Pare nt Error:%sn,strerror(err no);exit(1);int mailfd;while(1)if(mailfd=ope n(MAIL,0_RD0NLY)!=-1)fprin tf(stderr,%s,007);close(mailfd);sleep(SLEEP_TIME);你可以在默認(rèn)的路徑下創(chuàng)建你的郵箱文件,然后測試一下這個(gè)程序當(dāng)然這個(gè)程序 還有很多地方要改善的.我們后面會對這個(gè)小程序改善的,再看我的改善之前你可 以嘗試自己改 善一下
37、.比如讓用戶指定郵相的路徑和睡眠時(shí)間等等.相信自己可以 做到的.動手吧,勇敢的探險(xiǎn)者.好了進(jìn)程一節(jié)的內(nèi)容我們就先學(xué)到這里了.進(jìn)程是一個(gè)非常重要的概念,許多的程序都會用子進(jìn)程.創(chuàng)建一個(gè)子進(jìn)程是每一個(gè)程序員的基本要求!3)Linux 程序設(shè)計(jì)入門-文件操作Linux 下文件的操作、八 、-刖言:我們在這一節(jié)將要討論 linux 下文件操作的各個(gè)函數(shù).文件的創(chuàng)建和讀寫文件的各個(gè)屬性目錄文件的操作管道文件1。文件的創(chuàng)建和讀寫我假設(shè)你已經(jīng)知道了標(biāo)準(zhǔn)級的文件操作的各個(gè)函數(shù) (fopen,fread,fwrite 等等).當(dāng)然 如果你不清楚的話也不要著急.我們討論的系統(tǒng)級的文件操作實(shí)際上是為標(biāo)準(zhǔn)級文 件操作
38、服務(wù)的.當(dāng)我們需要打開一個(gè)文件進(jìn)行讀寫操作的時(shí)候,我們可以使用系統(tǒng)調(diào)用函數(shù) ope n. 使用完成以后我們調(diào)用另外一個(gè) close 函數(shù)進(jìn)行關(guān)閉操作.#in clude vfcn tl.h#i nclude #i nclude #i nclude int ope n(const char *path name,i nt flags);int ope n(const char *path name,i nt flags,mode_t mode);int close(i nt fd);open 函數(shù)有兩個(gè)形式.其中 path name 是我們要打開的文件名(包含路徑名稱,缺省是認(rèn)為在當(dāng)前路徑下面)
39、.flags 可以去下面的一個(gè)值或者是幾個(gè)值的組合.O_RDONLY:以只讀的方式打開文件.O_WRONLY:以只寫的方式打開文件.O_RDWR:以讀寫的方式打開文件.O_APPEND:以追加的方式打開文件.O_CREAT:創(chuàng)建一個(gè)文件.O_EXEC:如果使用了 O_CREAT 而且文件已經(jīng)存在,就會發(fā)生一個(gè)錯(cuò)誤O_NOBLOCK:以非阻塞的方式打開一個(gè)文件.O_TRUNC:如果文件已經(jīng)存在,則刪除文件的內(nèi)容前面三個(gè)標(biāo)志只能使用任意的一個(gè)如果使用了 O_CREATE 標(biāo)志,那么我們要使用open 的第二種形式.還要指定 mode 標(biāo)志,用來表示文件的訪問權(quán)限.mode 可以是以 下情況的組合.
40、-S_IRUSR 用戶可以讀 S_IWUSR 用戶可以寫S_IXUSR 用戶可以執(zhí)行 S_IRWXU 用戶可以讀寫執(zhí)行S_IRGRP 組可以讀 SWGRP 組可以寫S_IXGRP 組可以執(zhí)行 SRWXG 組可以讀寫執(zhí)行S_IROTH 其他人可以讀 S_IWOTH 其他人可以寫S_IXOTH 其他人可以執(zhí)行 S_IRWXO 其他人可以讀寫執(zhí)行S_ISUID 設(shè)置用戶執(zhí)行 ID S_ISGID 設(shè)置組的執(zhí)行 ID我們也可以用數(shù)字來代表各個(gè)位的標(biāo)志.Linux 總共用 5 個(gè)數(shù)字來表示文件的各種 權(quán)限.00000.第一位表示設(shè)置用戶ID.第二位表示設(shè)置組ID,第三位表示用戶自己的 權(quán)限位,第四位表示
41、組的權(quán)限,最后一位表示其他人的權(quán)限.每個(gè)數(shù)字可以取 1(執(zhí)行權(quán)限),2(寫權(quán)限),4(讀權(quán)限),0(什么也沒有)或者是這幾個(gè)值 的和.比如我們要創(chuàng)建一個(gè)用戶讀寫執(zhí)行,組沒有權(quán)限,其他人讀執(zhí)行的文件設(shè)置用戶 ID 位那么 我們可以使用的模式是-1(設(shè)置用戶 ID)O(組沒有設(shè)置)7(1+2+4)0(沒有權(quán)限, 使用缺省)5(1+4)即 10705:ope n(temp,0_CREAT,10705);如果我們打開文件成功,open 會返回一個(gè)文件描述符我們以后對文件的所有操作 就可以對這個(gè)文件描述符進(jìn)行操作了 當(dāng)我們操作完成以后,我們要關(guān)閉文件了,只要調(diào)用 close 就可以了,其中 fd 是我們
42、 要關(guān)閉的文件描述符文件打開了以后,我們就要對文件進(jìn)行讀寫了 我們可以調(diào)用函數(shù) read 和 write 進(jìn)行 文件的讀寫#i nclude ssize_t read(i nt fd, void *buffer,size_t coun t);ssize_t write(i nt fd, const void *buffer,size_t coun t);fd是我們要進(jìn)行讀寫操作的文件描述符buffer是我們要寫入文件內(nèi)容或讀出文件 內(nèi)容的內(nèi)存地址count 是我們要讀寫的字節(jié)數(shù)對于普通的文件 read 從指定的文件(fd)中讀取 count 字節(jié)到 buffer 緩沖區(qū)中(記住 我們必 須提供
43、一個(gè)足夠大的緩沖區(qū)),同時(shí)返回 count.如果 read 讀到了文件的結(jié)尾或者被一個(gè)信號所中斷,返回值會小于 count.如果是由 信號中 斷引起返回,而且沒有返回?cái)?shù)據(jù),read 會返回-1,且設(shè)置 errno 為 EINTR 當(dāng)程 序讀到了文件 結(jié)尾的時(shí)候,read 會返回 0 write 從 buffer 中寫 count 字節(jié)到文件 fd 中,成功時(shí)返回實(shí)際所寫的字節(jié)數(shù) 下面我們學(xué)習(xí)一個(gè)實(shí)例,這個(gè)實(shí)例用來拷貝文件#i nclude #in clude vfcn tLh#i nclude #i nclude #i nclude #i nclude #include #defi ne BU
44、FFER_SIZE 1024 int main (i nt argc,char *argv)int from_fd,to_fd;int bytes_read,bytes_write; char bufferBUFFER_SIZE;char *ptr;if(argc!=3)fprin tf(stderr,Usage:%s fromfile tofilena,argv0);exit(1);/*打開源文件*/if(from_fd=ope n(argv1,O_RDONLY)=-1)fprin tf(stderr,Ope n %s Error:%sn,argv1,strerror(err no);exi
45、t(1);/*創(chuàng)建目的文件*/if(to_fd=ope n(argv2,O_WRONLY|O_CREAT,SRUSR|SWUSR)=-1) fprin tf(stderr,Ope n %s Error:%sn,argv2,strerror(err no);exit(1);/*以下代碼是一個(gè)經(jīng)典的拷貝文件的代碼*/while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)/* 一個(gè)致命的錯(cuò)誤發(fā)生了 */if(bytes_read=-1)&(errno!=EINTR) break;else if(bytes_read0)ptr=buffer;whil
46、e(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 if(bytes_write0)pt 葉=bytes_write;bytes_read-=bytes_write; /*寫的時(shí)候發(fā)生的致命錯(cuò)誤*/if(bytes_write=-1)break;close(from_fd); close(to_fd);exit(
47、0);2。文件的各個(gè)屬性文件具有各種各樣的屬性,除了我們上面所知道的文件權(quán)限以外,文件還有創(chuàng)建時(shí) 間,大小等等屬性.有時(shí)侯我們要判斷文件是否可以進(jìn)行某種操作(讀,寫等等).這個(gè)時(shí)候我們可以使用acce ss 函數(shù).#i nclude int access(c onst char *path name,i nt mode);path name 是文件名稱,mode 是我們要判斷的屬性.可以取以下值或者是他們的組合R_OK 文件可以讀,W_OK 文件可以寫,X_OK 文件可以執(zhí)行,F(xiàn)_OK 文件存在.當(dāng)我 們測試成功時(shí),函數(shù)返回 0,否則如果有一個(gè)條件不符時(shí),返回-1.如果我們要獲得文件的其他屬性
48、,我們可以使用函數(shù) stat 或者 fstat.#i nclude #i nclude int stat(c onst char *file_ name,struct stat *buf);int fstat(i nt filedes,struct stat *buf);struct stat dev_t st_dev; /* 設(shè)備 */ ino_t st_i no; /* 節(jié)點(diǎn) */ mode_t st_mode; /* 模式 */ nlink_tst_nlink; /* 硬連接 */ uid_t st_uid; /* 用戶 ID */ gid_t st_gid; /* 組 ID */ de
49、v_t st_rdev; /*設(shè)備類型 */off_t st_off; /* 文件字節(jié)數(shù) */un sig ned long st_blksize; /* 塊大小 */ un sig ned long st_blocks; /* 塊數(shù) */ time_tst_atime; /*最后一次訪問時(shí)間*/ time_t st_mtime; /*最后一次修改時(shí)間*/ time_t st_ctime;/*最后一次改變時(shí)間(指屬性)*/ ;stat 用來判斷沒有打開的文件,而 fstat 用來判斷打開的文件.我們使用最多的屬性是 st_mode 通過著屬性我們可以判斷給定的文件是一個(gè)普通文件還是一個(gè)目錄,連
50、接等等.可以使用下面幾個(gè)宏來判斷.SSLNK(st_mode):是否是一個(gè)連接.SSREG 是否是一個(gè)常規(guī)文件.S_ISDIR 是否 是一個(gè)目錄 S_ISCHR 是否是一個(gè)字符設(shè)備.S_ISBLK 是否是一個(gè)塊設(shè)備S_ISFIFO 是否 是一個(gè) FIFO 文件.S_ISSOCK 是否是一個(gè) SOCKET 文件.我們會在 下面說明如何使用這幾個(gè)宏的.3。目錄文件的操作在我們編寫程序的時(shí)候,有時(shí)候會要得到我們當(dāng)前的工作路徑。C 庫函數(shù)提供了getcwd 來解決這個(gè)問題。#i nclude char *getcwd(char *buffer,size_t size);我們提供一個(gè) size 大小的
51、buffer,getcwd 會把我們當(dāng)前的路徑考到 buffer 中.如果 buffer太小,函數(shù)會返回-1 和一個(gè)錯(cuò)誤號.Linux 提供了大量的目錄操作函數(shù),我們學(xué)習(xí)幾個(gè)比較簡單和常用的函數(shù).#in clude #i nclude #in clude vfcn tl.h#i nclude #i nclude int mkdir(c onst char *path,mode_t mode);DIR *ope ndir(c onst char *path); struct dire nt *readdir(DIR *dir); void rewi nddir(DIR*dir);off_t te
52、lldir(DIR *dir);void seekdir(DIR *dir,off_t off);in t closedir(DIR *dir);struct dire nt long d_ino;off_t d_off;un sig ned short d_recle n;char d_nameNAME_MAX+1; /* 文件名稱 */mkdir 很容易就是我們創(chuàng)建一個(gè)目錄,opendir 打開一個(gè)目錄為以后讀做準(zhǔn)備.readdir 讀一個(gè)打開的目錄.rewinddir 是用來重讀目錄的和我們學(xué)的 rewind 函數(shù)一樣.closedir 是關(guān)閉 一個(gè)目錄.telldir 和 seekdi
53、r 類似與 ftee 和 fseek 函數(shù).下面我們開發(fā)一個(gè)小程序,這個(gè)程序有一個(gè)參數(shù).如果這個(gè)參數(shù)是一個(gè)文件名,我們 輸出這個(gè)文件的大小和最后修改的時(shí)間,如果是一個(gè)目錄我們輸出這個(gè)目錄下所 有文件的大小和 修改時(shí)間.#i nclude #i nclude #i nclude verrno .h#i nclude #i nclude #in clude #in clude static int get_file_size_time(c on st char *file name)struct stat statbuf;if(stat(file name,&statbuf)=-1)pri
54、n tf(Get stat o n %s Error:%sn,file name,strerror(err no);return(-1);if(S_I SDIR(statbuf.st_mode)return(1);if(S_I SREG(statbuf.st_mode)prin tf(%s size:%ld bytestmodified at %s,file name,statbuf.st_size,ctime(&statbuf.st_mtime);return(0);int main (i nt argc,char *argv)DIR *dirp;struct dire nt *di
55、re ntp;int stats;if(argc!=2)prin tf(Usage:%s file namen a,argvO);exit(1);if(stats=get_file_size_time(argv1)=0)|(stats=-1)exit(1);if(dirp=ope ndir(argv1)=NULL)prin tf(Ope n Directory %s Error:%sn,argv1,strerror(err no);exit(1);while(dire ntp=readdir(dirp)!=NULL)if(get_file_size_time(dire ntp-d_ name)
56、=-1)break; closedir(dirp);exit(1);4。管道文件Linux 提供了許多的過濾和重定向程序,比如 more cat等等.還提供了 | in t pipe(i nt fildes2);pipe 調(diào)用可以創(chuàng)建一個(gè)管道(通信緩沖區(qū)).當(dāng)調(diào)用成功時(shí),我們可以訪問文件描述符fild es0,fildes1.其中 fildes0是用來讀的文件描述符,而 fildes1是用來寫的文件 描述符.在實(shí)際使用中我們是通過創(chuàng)建一個(gè)子進(jìn)程,然后一個(gè)進(jìn)程寫,一個(gè)進(jìn)程讀來使用的. 關(guān)于進(jìn)程通信的詳細(xì)情況請查看進(jìn)程通信#i nclude #i nclude #i nclude #include
57、 #i nclude verrno .h#i nclude #i nclude #defi ne BUFFER 255int main (i nt argc,char *argv)char bufferBUFFER+1;int fd2;if(argc!=2)fprintf(stderr,Usage:%s stringna,argvO); exit(1);if(pipe(fd)!=0)fprin tf(stderr,Pipe Error:%sn a,strerror(errino); exit(1);if(fork()=O)close(fd0);prin tf(Child%d Write to
58、pipena,getpid(); snprin tf(buffer,BUFFER,%s,argv1);write(fd1,buffer,strle n(buffer);prin tf(Child%d Quitna,getpid();exit(O);elseclose(fd1);prin tf(Pare nt%d Read from pipena,getpid(); memset(buffer,0,BUFFER+1);read(fdO,buffer,BUFFER);printf(Parent%d Read:%sn,getpid(),buffer); exit(1);為了實(shí)現(xiàn)重定向操作,我們需要調(diào)用另
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 2024版中英文二手房買賣合同范本
- 2024年物業(yè)管理服務(wù)采購合同
- 17 爬天都峰 說課稿-2024-2025學(xué)年語文四年級上冊統(tǒng)編版
- 專業(yè)繪畫合作合同2024版版B版
- 19 懷疑與學(xué)問2024-2025學(xué)年九年級語文上冊同步說課稿(河北專版)
- 【呼吸內(nèi)科】為了患者健康的呼吸
- 福建省南平市武夷山上梅中學(xué)2021-2022學(xué)年高二化學(xué)上學(xué)期期末試題含解析
- 2025年度國際工程項(xiàng)目承包合同5篇
- 2024年魚池生態(tài)旅游租賃合同3篇
- 七夕運(yùn)動情緣盛宴
- DB12-T 1124-2022 防雷裝置檢測點(diǎn)分類及確定方法
- 2024年海南公務(wù)員考試申論試題(A卷)
- 人教版三年級上冊萬以內(nèi)的數(shù)加減法豎式計(jì)算300道及答案
- 2024年1月遼寧省普通高中學(xué)業(yè)水平合格性考試物理試題(含答案解析)
- 網(wǎng)絡(luò)安全中的量子密碼學(xué)與未來安全技術(shù)考核試卷
- 海堤工程施工組織設(shè)計(jì)
- 走進(jìn)創(chuàng)業(yè)學(xué)習(xí)通超星期末考試答案章節(jié)答案2024年
- 2024年石油石化技能考試-鉆井液工考試近5年真題附答案
- 世界經(jīng)典神話與傳說故事閱讀測試(四)
- 2024年第五屆插花花藝行業(yè)技能競賽理論考試題庫(含答案)
- 軍事理論(2024年版)學(xué)習(xí)通超星期末考試答案章節(jié)答案2024年
評論
0/150
提交評論