Linux操作系統(tǒng)下C語言編程入門_第1頁
Linux操作系統(tǒng)下C語言編程入門_第2頁
Linux操作系統(tǒng)下C語言編程入門_第3頁
Linux操作系統(tǒng)下C語言編程入門_第4頁
Linux操作系統(tǒng)下C語言編程入門_第5頁
免費預覽已結(jié)束,剩余26頁可下載查看

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、linux操作系統(tǒng)下c語言編程入門(一)目錄介紹1)Linux程序設(shè)計入門-基礎(chǔ)知識2)Linux程序設(shè)計入門-進程介紹3)Linux程序設(shè)計入門-文件操作4)Linux程序設(shè)計入門-時間概念5)Linux程序設(shè)計入門-信號處理6)Linux程序設(shè)計入門-消息管理7)Linux程序設(shè)計入門-線程操作8)Linux程序設(shè)計入門-網(wǎng)絡編程9)Linux下C開發(fā)工具介紹(二)具體內(nèi)容1)Linux程序設(shè)計入門-基礎(chǔ)知識Linux下C語言編程基礎(chǔ)知識前言:這篇文章介紹在LINUX下進行C語言編程所需要的基礎(chǔ)知識.在這篇文章當中我們將會學到以下內(nèi)容:源程序編譯Makefile的編寫程序庫的鏈接程序的調(diào)試

2、頭文件和系統(tǒng)求助1 .源程序的編譯在Linux下面,如果要編譯一個C語言源程序,我們要使用GNU勺gcc編譯器.下面我們以一個實例來說明如何使用gcc編譯器.假設(shè)我們有下面一個非常簡單的源程序(hello.c):intmain(intargc,char*argv)printf("HelloLinuxn");要編譯這個程序,我們只要在命令行下執(zhí)行:gcc-ohellohello.cgcc編譯器就會為我們生成一個hello的可執(zhí)行文件.執(zhí)行./hello就可以看到程序的輸出結(jié)果了.命令行中g(shù)cc表示我們是用gcc來編譯我們的源程序,-o選項表示我們要求編譯器給我們車出的可執(zhí)行文

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

4、clude"mytool2.h"intmain(intargc,char*argv)(mytool1_print("hello");mytool2_print("hello");/*mytool1.h*/#ifndef_MYTOOL_1_H#define_MYTOOL_1_Hvoidmytool1_print(char*print_str);#endif/*mytool1.c*/#include"mytool1.h"voidmytool1_print(char*print_str)(printf("Thi

5、sismytool1print%sn",print_str);/*mytool2.h*/#ifndef_MYTOOL_2_H#define_MYTOOL_2_Hvoidmytool2_print(char*print_str);#endif/*mytool2.c*/#include"mytool2.h"voidmytool2_print(char*print_str)(printf("Thisismytool2print%sn",print_str);當然由于這個程序是很短的我們可以這樣來編譯gcc-cmain.cgcc-cmytooll.cg

6、cc-cmytool2.cgcc-omainmain.omytooll.omytool2.o這樣的話我們也可以產(chǎn)生main程序,而且也不時很麻煩.但是如果我們考慮一下如果有一天我們修改了其中的一個文件(比如說mytooll.c)那么我們難道還要重新輸入上面的命令?也許你會說,這個很容易解決啊,我寫一個SHELL腳本,讓她幫我去完成不就可以了.是的對于這個程序來說,是可以起到作用的.但是當我們把事情想的更復雜一點,如果我們的程序有幾百個源程序的時候,難道也要編譯器重新一個一個的去編譯?為此,聰明的程序員們想出了一個很好的工具來做這件事情,這就是make.我們只要執(zhí)行一下make,就可以把上面的問

7、題解決掉.在我們執(zhí)行make之前,我們要先編寫一個非常重要的文件.-Makefile.對于上面的那個程序來說,可能的一個Makefile的文件是:#這是上面那個程序的Makefile文件main:main.omytool1.omytool2.ogcc-omainmain.omytool1.omytool2.omain.o:main.cmytool1.hmytool2.hgcc-cmain.cmytool1.o:mytool1.cmytool1.hgcc-cmytool1.cmytool2.o:mytool2.cmytool2.hgcc-cmytool2.c有了這個Makefile文件,不過我們

8、什么時候修改了源程序當中的什么文件,我們只要執(zhí)行make命令,我們的編譯器都只會去編譯和我們修改的文件有關(guān)的文件,其它的文件她連理都不想去理的.下面我們學習Makefile是如何編寫的.在Makefile中#開始的行都是注釋行.Makefile中最重要的是描述文件的依賴關(guān)系的說明.一般的格式是:target:componentsTABrule第一行表示的是依賴關(guān)系.第二行是規(guī)則.比如說我們上面的那個Makefile文件的第二行main:main.omytool1.omytool2.o表示我們的目標(target)main的依賴對象(components)是main.omytool1.omyto

9、ol2.o當倚賴的對象在目標修改后修改的話,就要去執(zhí)行規(guī)則一行所指定的命令.就象我們的上面那個Makefile第三行所說的一樣要執(zhí)行g(shù)cc-omainmain.omytool1.omytool2.o注意規(guī)則一行中的TAB表示那里是一個TAB鍵Makefile有三個非常有用的變量.分別是$,$人,$<代表的意義分別是:$-目標文件,$人-所有的依賴文件,$<-第一個依賴文件.如果我們使用上面三個變量,那么我們可以簡化我們的Make巾le文件為:#這是簡化后的Makefilemain:main.omytool1.omytool2.ogcc-o$Amain.o:main.cmytool1

10、.hmytool2.hgcc-c$<mytool1.o:mytool1.cmytooll.hgcc-c$<mytool2.o:mytool2.cmytool2.hgcc-c$<經(jīng)過簡化后我們的Make巾le是簡單了一點,不過人們有時候還想簡單一點.這里我們學習一個Make巾le的缺省規(guī)則.c.o:gcc-c$<這個規(guī)則表示所有的.o文件都是依賴于相應的.c文件的.例如mytool.o依賴于mytool.c這樣Make巾le還可以變?yōu)椋?這是再一次簡化后的Makefilemain:main.omytool1.omytool2.ogcc-o$A.c.o:gcc-c$<

11、好了,我們的Makefile也差不多了,如果想知道更多的關(guān)于Makefile規(guī)則可以查看相應的文檔.3 .程序庫的鏈接試著編譯下面這個程序/*temp.c*/#include<math.h>intmain(intargc,char*argv)(doublevalue;printf("Value:%fn",value);)這個程序相當簡單,但是當我們用gcc-otemptemp.c編譯時會出現(xiàn)下面所示的錯誤./tmp/cc33Kydu.o:Infunction'main':/tmp/cc33Kydu.o(.text+0xe):undefinedre

12、ferenceto'log'collect2:ldreturned1exitstatus出現(xiàn)這個錯誤是因為編譯器找不到10g的具體實現(xiàn).雖然我們包括了正確的頭文件,但是我們在編譯的時候還是要連接確定的庫.在Linux下,為了使用數(shù)學函數(shù),我們必須和數(shù)學庫連接,為此我們要加入-lm選項.gcc-otemptemp.c-lm這樣才能夠正確的編譯.也許有人要問,前面我們用printf函數(shù)的時候怎么沒有連接庫呢?是這樣的,對于一些常用的函數(shù)的實現(xiàn),gcc編譯器會自動去連接一些常用庫,這樣我們就沒有必要自己去指定了.有時候我們在編譯程序的時候還要指定庫的路徑,這個時候我們要用到編譯器的-

13、L選項指定路徑.比如說我們有一個庫在/home/hoyt/mylib下,這樣我們編譯的時候還要加上-L/home/hoyt/mylib.對于一些標準庫來說,我們沒有必要指出路徑.只要它們在其缺省庫的路徑下就可以了.系統(tǒng)的缺省庫的路徑/lib/usr/lib/usr/local/lib在這三個路徑下面的庫,我們可以不指定路徑.還有一個問題,有時候我們使用了某個函數(shù),但是我們不知道庫的名字,這個時候怎么辦呢?很抱歉,對于這個問題我也不知道答案,我只有一個傻辦法.首先,我到標準庫路徑下面去找看看有沒有和我用的函數(shù)相關(guān)的庫,我就這樣找到了線程(thread)函數(shù)的庫文件(libpthread.a).當

14、然,如果找不到,只有一個笨方法.比如我要找sin這個函數(shù)所在的庫.就只好用nm-o/lib/*.so|grepsin;/sin命令,然后看/sin文件,到那里面去找了.在sin文件當中,我會找到這樣的一行l(wèi)ibm-2.12so:00009fa0Wsin這樣我就知道了sin在libm-2.1.2.so庫里面,我用-lm選項就可以了(去掉前面的lib和后面的版本標志,就剩下m了所以是-lm).如果你知道怎么找,請趕快告訴我,我回非常感激的.謝謝!4 .程序的調(diào)試我們編寫的程序不太可能一次性就會成功的,在我們的程序當中,會出現(xiàn)許許多多我們想不到的錯誤,這個時候我們就要對我們的程序進行調(diào)試了.最常用的

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

16、read這個函數(shù)的確切形式,我們只要執(zhí)行manfread系統(tǒng)就會輸出這函數(shù)的詳細解釋的.和這個函數(shù)所在的頭文件stdio.h說明了.如果我們要write這個函數(shù)的說明,當我們執(zhí)行manwrite時,輸出的結(jié)果卻不是我們所需要的.因為我們要的是write這個函數(shù)的說明,可是出來的卻是write這個命令的說明.為了得到write的函數(shù)說明我們要用man2write.2表示我們用的write這個函數(shù)是系統(tǒng)調(diào)用函數(shù),還有一個我們常用的是3表示函數(shù)是C的庫函數(shù).記住不管什么時候,man都是我們的最好助手.好了,這一章就講這么多了,有了這些知識我們就可以進入激動人心的Linux下的C程序探險活動.2)Li

17、nux程序設(shè)計入門-進程介紹Linux下進程的創(chuàng)建前言:這篇文章是用來介紹在Linux下和進程相關(guān)的各個概念.我們將會學到:進程的概念進程的身份進程的創(chuàng)建守護進程的創(chuàng)建1.進程的概念Linux操作系統(tǒng)是面向多用戶的.在同一時間可以有許多用戶向操作系統(tǒng)發(fā)出各種命令.那么操作系統(tǒng)是怎么實現(xiàn)多用戶的環(huán)境呢?在現(xiàn)代的操作系統(tǒng)里面,都有程序和進程的概念.那么什么是程序,什么是進程呢?通俗的講程序是一個包含可以執(zhí)行代碼的文件,遑個靜態(tài)的文件.而進程是一個開始執(zhí)行但是還沒有結(jié)束的程序的實例.就是可執(zhí)行文件的具體實現(xiàn).一個程序可能有許多進程,而每一個進程又可以有許多子進程.依次循環(huán)下去,而產(chǎn)生子孫進程.當程序

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

19、么我們怎么得到進程的ID呢?系統(tǒng)調(diào)用getpid可以得到進程的ID,而getppid可以得到父進程(創(chuàng)建調(diào)用該函數(shù)進程的進程)的2.#include<unistd>pid_tgetpid(void);pid_tgetppid(void);進程是為程序服務的,而程序是為了用戶服務的.系統(tǒng)為了找到進程的用戶名,還為進程和用戶建立聯(lián)系.這個用戶稱為進程的所有者.相應的每一個用戶也有一個用戶ID.通過系統(tǒng)調(diào)用getuid可以得到進程的所有者的ID.由于進程要用到一些資源,而Linux對系統(tǒng)資源是進行保護的,為了獲取一定資源進程還有一個有效用戶ID.這個ID和系統(tǒng)的資源使用有關(guān),涉及到進程的

20、權(quán)限.通過系統(tǒng)調(diào)用geteuid我們可以得到進程的有效用戶ID.和用戶ID相對應進程還有一個組ID和有效組ID系統(tǒng)調(diào)用getgid和getegid可以分別得到組ID和有效組ID#include<unistd>#include<sys/types.h>uid_tgetuid(void);uid_tgeteuid(void);gid_tgetgid(void);git_tgetegid(void);有時候我們還會對用戶的其他信息感興趣(登錄名等等),這個時候我們可以調(diào)用getpwuid來得到.structpasswdchar*pw_name;/*登錄名稱*/char*pw_

21、passwd;/*登錄口令*/uid_tpw_uid;/*用戶ID*/gid_tpw_gid;/*用戶組ID*/char*pw_gecos;/*用戶的真名*/char*pw_dir;/*用戶的目錄*/char*pw_shell;/*用戶的SHELL*/);#include<pwd.h>#include<sys/types.h>structpasswd*getpwuid(uid_tuid);下面我們學習一個實例來實踐一下上面我們所學習的幾個函數(shù)#include<unistd.h>#include<pwd.h>#include<sys/type

22、s.h>#include<stdio.h>intmain(intargc,char*argv)pid_tmy_pid,parent_pid;uid_tmy_uid,my_euid;gid_tmy_gid,my_egid;structpasswd*my_info;my_pid=getpid();parent_pid=getppid();my_uid=getuid();my_euid=geteuid();my_gid=getgid();my_egid=getegid();my_info=getpwuid(my_uid);printf("ProcessID:%ldn&qu

23、ot;,my_pid);printf("ParentID:%ldn",parent_pid);printf("UserID:%ldn",my_uid);printf("EffectiveUserID:%ldn",my_euid);printf("GroupID:%ld'n",my_gid);printf("EffectiveGroupID:%ldn",my_egid):if(my_info)printf("MyLoginName:%sn",my_info->pw

24、_name);printf("MyPassword:%sn",my_info->pw_passwd);printf("MyUserID:%ldn",my_info->pw_uid);printf("MyGroupID:%ldn",my_info->pw_gid);printf("MyRealName:%sn",my_info->pw_gecos);printf("MyHomeDir:%sn",my_info->pw_dir);printf("MyWorkS

25、hell:%sn",my_info->pw_shell);3。進程的創(chuàng)建創(chuàng)建一個進程的系統(tǒng)調(diào)用很簡單.我們只要調(diào)用fork函數(shù)就可以了.#include<unistd.h>pid_tfork();當一個進程調(diào)用了fork以后,系統(tǒng)會創(chuàng)建一個子進程.這個子進程和父進程不同的地方只有他的進程ID和父進程ID,其他的都是一樣.就象父進程克隆(clone)自己一樣.當然創(chuàng)建兩個一模一樣的進程是沒有意義的.為了區(qū)分父進程和子進程,我們必須跟蹤fork的返回值.當fork掉用失敗的時候(內(nèi)存不足或者是用戶的最大進程數(shù)已到)fork返回-1,否則fork的返回值有重要的作用.對于

26、父進程fork返回子進程的ID,而對于fork子進程返回0.我們就是根據(jù)這個返回值來區(qū)分父子進程的.父進程為什么要創(chuàng)建子進程呢?前面我們已經(jīng)說過了Linux是一個多用戶操作系統(tǒng),在同一時間會有許多的用戶在爭奪系統(tǒng)的資源.有時進程為了早一點完成任務就創(chuàng)建子進程來爭奪資源.一旦子進程被創(chuàng)建,父子進程一起從fork處繼續(xù)執(zhí)行,相互競爭系統(tǒng)的資源.有時候我們希望子進程繼續(xù)執(zhí)行,而父進程阻塞直到子進程完成任務.這個時候我們可以調(diào)用wait或者waitpid系統(tǒng)調(diào)用.#include<sys/types.h>#include<sys/wait.h>pid_twait(int*sta

27、t_loc);pid_twaitpid(pid_tpid,int*stat_loc,intoptions);wait系統(tǒng)調(diào)用會使父進程阻塞直到一個子進程結(jié)束或者是父進程接受到了一個信號.如果沒有父進程沒有子進程或者他的子進程已經(jīng)結(jié)束wait回立即返回.成功時(因一個子進程結(jié)束)wait將返回子進程的ID,否則返回-1,并設(shè)置全局變量errno.stat_loc是子進程的退出狀態(tài).子進程調(diào)用exit,_exit或者是return來設(shè)置這個值.為了得到這個值Linux定義了幾個宏來測試這個返回值.WIFEXITED:判斷子進程退出值是非0WEXITSTATU第U斷子進程的退出值(當子進程退出時非0

28、).WIFSIGNALED:子進程由于有沒有獲得的信號而退出.WTERMSIGF進程沒有獲得的信號(在WIFSIGNALEM真時才有意義).waitpid等待指定的子進程直到子進程返回.如果pid為正值則等待指定的進程(pid).如果為0則等待任何一個組ID和調(diào)用者的組ID相同的進程.為-1時等同于wait調(diào)用.小于-1時等待任何一個組ID等于pid絕對值的進程.stat_loc和wait的意義一樣.options可以決定父進程的狀態(tài).可以取兩個值WNOHANG:進程立即返回當沒有子進程存在時.WUNTACHE當子進程結(jié)束時waitpid返回,但是子進程的退出狀態(tài)不可得到.父進程創(chuàng)建子進程后,

29、子進程一般要執(zhí)行不同的程序.為了調(diào)用系統(tǒng)程序,我們可以使用系統(tǒng)調(diào)用exec族調(diào)用.exec族調(diào)用有著5個函數(shù).#include<unistd.h>intexecl(constchar*path,constchar*arg,.);intexeclp(constchar*file,constchar*arg,.);intexecle(constchar*path,constchar*arg,.);intexecv(constchar*path,char*constargv);intexecvp(constchar*file,char*constargv口);exec族調(diào)用可以執(zhí)行給定程

30、序.關(guān)于exec族調(diào)用的詳細解說可以參考系統(tǒng)手冊(manexecl).下面我們來學習一個實例.注意編譯的時候要加-lm以便連接數(shù)學函數(shù)庫.#include<unistd.h>#include<sys/types.h>#include<sys/wait.h>#include<stdio.h>#include<errno.h>#include<math.h>voidmain(void)pid_tchild;intstatus;printf("Thiswilldemostratehowtogetchildstatusn

31、");if(child=fork()=-1)printf("ForkError:%sn",strerror(errno);exit(1);elseif(child=0)(inti;printf("Iamthechild:%ldn",getpid();for(i=0;i<1000000;i+)sin(i);i=5;printf("Iexitwith%dn",i);exit(i);while(child=wait(&status)=-1)&(errno=EINTR);if(child=-1)printf(&

32、quot;WaitError:%sn",strerror(errno);elseif(!status)printf("Child%ldterminatednormallyreturnstatusiszeron",child);elseif(WIFEXITED(status)printf("Child%ldterminatednormallyreturnstatusis%dn",child,WEXITSTATUS(status);elseif(WIFSIGNALED(status)printf("Child%ldterminateddu

33、etosignal%dznotcaughtn",child,WTERMSIG(status);strerror函數(shù)會返回一個指定的錯誤號的錯誤信息的字符串4。守護進程的創(chuàng)建如果彳在DOS寸代編寫過程序,那么你也許知道在DOST為了編寫一個常駐內(nèi)存的程序我們要編寫多少代碼了.相反如果在Linux下編寫一個"常駐內(nèi)存"的程序卻是很容易的.我們只要幾行代碼就可以做到.實際上由于Linux是多任務操作系統(tǒng),我們就是不編寫代碼也可以把一個程序放到后臺去執(zhí)行的.我們只要在命令后面加上&符號SHELL就會把我們的程序放到后臺去運行的.這里我們"開發(fā)"

34、一個后臺檢查郵件的程序.這個程序每隔一個指定的時間回去檢查我們的郵箱,如果發(fā)現(xiàn)我們有郵件了,會不斷的報警(通過機箱上的小喇叭來發(fā)出聲音).后面有這個函數(shù)的加強版本后臺進程的創(chuàng)建思想:首先父進程創(chuàng)建一個子進程.然后子進程殺死父進程(是不是很無情?).信號處理所有的工作由子進程來處理.#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<errno.h>#include<fcntl.h>#include<s

35、ignal.h>/*Linux的默任個人的郵箱地址是/var/spool/mail/用戶的登錄名*/#defineMAIL"/var/spool/mail/hoyt"/*睡眠10秒鐘*/#defineSLEEP_TIME10main(void)pid_tchild;if(child=fork()=-1)printf("ForkError:%sn",strerror(errno);exit(1);elseif(child>0)while(1);if(kill(getppid(),SIGTERM)=-1)printf("KillPare

36、ntError:%sn",strerror(errno);exit(1);intmailfd;while(1)if(mailfd=open(MAIL,O_RDONLY)!=-1)fprintf(stderr,"%s","007");close(mailfd);)sleep(SLEEP_TIME);)你可以在默認的路徑下創(chuàng)建你的郵箱文件,然后測試一下這個程序.當然這個程序還有很多地方要改善的.我們后面會對這個小程序改善的,再看我的改善之前你可以嘗試自己改善一下.比如讓用戶指定郵箱的路徑和睡眠時間等等.相信自己可以做到的.動手吧,勇敢的探險者.好了

37、進程一節(jié)的內(nèi)容我們就先學到這里了.進程是一個非常重要的概念,許多的程序都會用子進程.創(chuàng)建一個子進程是每一個程序員的基本要求!3)Linux程序設(shè)計入門-文件操作Linux下文件的操作前言:我們在這一節(jié)將要討論linux下文件操作的各個函數(shù).文件的創(chuàng)建和讀寫文件的各個屬性目錄文件的操作管道文件1.文件的創(chuàng)建和讀寫我假設(shè)你已經(jīng)知道了標準級的文件操作的各個函數(shù)(fopen,fread,fwrite等等).當然如果你不清楚的話也不要著急.我們討論的系統(tǒng)級的文件操作實際上是為標準級文件操作服務的.當我們需要打開一個文件進行讀寫操作的時候,我們可以使用系統(tǒng)調(diào)用函數(shù)open.使用完成以后我們調(diào)用另外一個cl

38、ose函數(shù)進行關(guān)閉操作.#include<fcntl.h>#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>intopen(constchar*pathname,intflags);intopen(constchar*pathname,intflags,mode_tmode);intclose(intfd);open函數(shù)有兩個形式.其中pathname是我們要打開的文件名(包含路彳5名稱,缺省是認為在當前路徑下面).flags可以去下面的一個值或者是幾個值的組合.O_RDONLW

39、只讀的方式打開文件o_wronlw只寫的方式打開文件O_RDWRU賣寫的方式打開文件.O_APPENM追加的方式打開文件.O_CREA醐建一個文件.O_EXEC$果使用了O_CREA而且文件已經(jīng)存在,就會發(fā)生一個錯誤.O_NOBLOC粗非阻塞的方式打開一個文件.O_TRUN或果文件已經(jīng)存在,則刪除文件的內(nèi)容.前面三個標志只能使用任意的一個.如果使用了O_CREAT標志,那么我們要使用open的第二種形式.還要指定mode標志,用來表示文件的訪問權(quán)限.mode可以是以下情況的組合.S_IRUSR用戶可以讀S_IWUSR用戶可以寫S_IXUSR用戶可以執(zhí)行S_IRWXU用戶可以讀寫執(zhí)行S_IRGR

40、P組可以讀S_IWGRP組可以寫S_IXGRP組可以執(zhí)行S_IRWXG組可以讀寫執(zhí)行S_IROTH其他人可以讀S_IWOTH其他人可以寫S_IXOTH其他人可以執(zhí)行S_IRWXO其他人可以讀寫執(zhí)行S_ISUID設(shè)置用戶執(zhí)行IDS_ISGID設(shè)置組的執(zhí)行ID我們也可以用數(shù)字來彳t表各個位的標志.Linux總共用5個數(shù)字來表示文件的各種權(quán)限00000.第一位表示設(shè)置用戶ID.第二位表示設(shè)置組ID,第三位表示用戶自己的權(quán)限位,第四位表示組的權(quán)限,最后一位表示其他人的權(quán)限.每個數(shù)字可以取1(執(zhí)行權(quán)限),2(寫權(quán)限),4(讀權(quán)限),0(什么也沒有)或者是這幾個值的和.比如我們要創(chuàng)建一個用戶讀寫執(zhí)行組沒有

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

42、e_tread(intfd,void*buffer,size_tcount);ssize_twrite(intfd,constvoid*buffer,size_tcount);fd是我們要進行讀寫操作的文件描述符,buffer是我們要寫入文件內(nèi)容或讀出文件內(nèi)容的內(nèi)存地址.count是我們要讀寫的字節(jié)數(shù).對于普通的文件read從指定的文件(fd)中讀取count字節(jié)到buffer緩沖區(qū)中(記住我們必須提供一個足夠大的緩沖區(qū)),同時返回count.如果read讀到了文件的結(jié)尾或者被一個信號所中斷,返回值會小于count.如果是由信號中斷引起返回,而且沒有返回數(shù)據(jù),read會返回-1,且設(shè)置errn

43、o為EINTR.當程序讀到了文件結(jié)尾的時候,read會返回0.write從buffer中寫count字節(jié)到文件fd中,成功時返回實際所寫的字節(jié)數(shù).下面我們學習一個實例,這個實例用來拷貝文件.#include<fcntl.h>#include<stdio.h>#include<sys/types.h>#include<sys/stat.h>#include<errno.h>#include<string.h>#defineBUFFER_SIZE1024intmain(intargc,char*argv)intfrom_fd,

44、to_fd;intbytes_read,bytes_write;charbufferBUFFER_SIZE;char*ptr;if(argc!=3)fprintf(stderr,"Usage:%sfromfiletofilena",argv0);exit(1);/*打開源文件*/if(from_fd=open(argv1,O_RDONLY)=-1)fprintf(stderr,"Open%sError:%sn",argv1,strerror(errno);exit(1);/*創(chuàng)建目的文件*/if(to_fd=open(argv2,O_WRONLY|O_C

45、REAT,S_IRUSR|S_IWUSR)=-1)fprintf(stderr,"Open%sError:%sn",argv2,strerror(errno);exit(1);/*以下代碼是一個經(jīng)典的拷貝文件的代碼*/while(bytes_read=read(from_fd,buffer,BUFFER_SIZE)(/*一個致命的錯誤發(fā)生了*/if(bytes_read=-1)&&(errno!=EINTR)break;elseif(bytes_read>0)(ptr=buffer;while(bytes_write=write(to_fd,ptr,b

46、ytes_read)/*一個致命錯誤發(fā)生了*/if(bytes_write=-1)&&(errno!=EINTR)break;/*寫完了所有讀的字節(jié)*/elseif(bytes_write=bytes_read)break;/*只寫了一部分,繼續(xù)寫*/elseif(bytes_write>0)ptr+=bytes_write;bytes_read-=bytes_write;/*寫的時候發(fā)生的致命錯誤*/if(bytes_write=-1)break;close(from_fd);close(to_fd);exit(0);2。文件的各個屬性文件具有各種各樣的屬性,除了我們上

47、面所知道的文件權(quán)限以外,文件還有創(chuàng)建時間,大小等等屬性.有時侯我們要判斷文件是否可以進行某種操作(讀,寫等等).這個時候我們可以使用access函數(shù).#include<unistd.h>intaccess(constchar*pathname,intmode);pathname:是文件名稱,mode是我們要判斷的屬性.可以取以下值或者是他們的組合.R_OKC件可以讀,W_OKt件可以寫,X_OK文件可以執(zhí)行,F(xiàn)_OK文件存在.當我們測試成功時,函數(shù)返回0,否則如果有一個條件不符時,返回-1.如果我們要獲得文件的其他屬性,我們可以使用函數(shù)stat或者fstat.#include<

48、;sys/stat.h>#include<unistd.h>intstat(constchar*file_name,structstat*buf);intfstat(intfiledes,structstat*buf);structstatdev_tst_dev;/*設(shè)備*/ino_tst_ino;/*節(jié)點*/mode_tst_mode;/*模式*/nlink_tst_nlink;/*硬連接*/uid_tst_uid;/*用戶ID*/gid_tst_gid;/*組ID*/dev_tst_rdev;/*設(shè)備類型*/off_tst_off;/*文件字節(jié)數(shù)*/unsignedlon

49、gst_blksize;/*塊大小*/unsignedlongst_blocks;/*塊數(shù)*/time_tst_atime;/*time_tst_mtime;/*time_tst_ctime;/*最后一次訪問時間*/最后一次修改時間*/最后一次改變時間(指屬性)*/);stat用來判斷沒有打開的文件,而fstat用來判斷打開的文件.我們使用最多的屬性是st_mode.通過這屬性我們可以判斷給定的文件是一個普通文件還是一個目錄,連接等等.可以使用下面幾個宏來判斷.S_ISLNK(st_mode):是否是一個連接.S_ISREG是否是一個常規(guī)文件.S_ISDIR是否是一個目錄S_ISCHR是否是一

50、個字符設(shè)備.S_ISBLK是否是一個塊設(shè)備S_ISFIFO是否是一個FIFO文件.S_ISSOCK是否是一個SOCKETt件.我們會在下面說明如何使用這幾個宏的.3。目錄文件的操作在我們編寫程序的時候,有時候會要得到我們當前的工作路徑。C庫函數(shù)提供了getcwd來解決這個問題。#include<unistd.h>char*getcwd(char*buffer,size_tsize);我們提供一個size大小的buffer,getcwd會把我們當前的路徑考到buffer中.如果buffer太小,函數(shù)會返回-1和一個錯誤號.Linux提供了大量的目錄操作函數(shù),我們學習幾個比較簡單和常用

51、的函數(shù).#include<dirent.h>#include<unistd.h>#include<fcntl.h>#include<sys/types.h>#include<sys/stat.h>intmkdir(constchar*path,mode_tmode);DIR*opendir(constchar*path);structdirent*readdir(DIR*dir);voidrewinddir(DIR*dir);off_ttelldir(DIR*dir);voidseekdir(DIR*dir,off_toff);int

52、closedir(DIR*dir);structdirentlongd_ino;off_td_off;unsignedshortd_reclen;chard_nameNAME_MAX+1;/*文件名稱*/mkdir很容易就是我們創(chuàng)建一個目錄,opendir打開一個目錄為以后讀做準備.readdir讀一個打開的目錄.rewinddir是用來重讀目錄白和我們學的rewind函數(shù)一樣.closedir是關(guān)閉一個目錄.telldir和seekdir類似與ftee和fseek函數(shù).下面我們開發(fā)一個小程序,這個程序有一個參數(shù).如果這個參數(shù)是一個文件名,我們輸出這個文件的大小和最后修改的時間,如果是一個目錄

53、我們輸出這個目錄下所有文件的大小和修改時間#include<unistd.h>#include<stdio.h>#include<errno.h>#include<sys/types.h>#include<sys/stat.h>#include<dirent.h>include<time.h>staticintget_file_size_time(constchar*filename)structstatstatbuf;if(stat(filename,&statbuf)=-1)printf("

54、;Getstaton%sError:%sn",filename,strerror(errno);return(-1);if(S_ISDIR(statbuf.st_mode)return;if(S_ISREG(statbuf.st_mode)printf("%ssize:%ldbytestmodifiedat%s",filename,statbuf.st_size,ctime(&statbuf.st_mtime);return(0);intmain(intargc,char*argv)DIR*dirp;structdirent*direntp;intstat

55、s;if(argc!=2)printf("Usage:%sfilenamena",argv0);exit(1);if(stats=get_file_size_time(argv1)=0)|(stats=-1)exit(1);if(dirp=opendir(argv1)=NULL)printf("OpenDirectory%sError:%sn",argv1,strerror(errno);exit(1);while(direntp=readdir(dirp)!=NULL)if(get_file_size_time(direntp-<d_name)=

56、-1)break;closedir(dirp);exit(1);4。管道文件Linux提供了許多的過濾和重定向程序,比如morecat等等.還提供了<>|<<等等重定向操作符.在這些過濾和重定向程序當中,都用到了管道這種特殊的文件.系統(tǒng)調(diào)用pipe可以創(chuàng)建一個管道.#include<unistd.h>intpipe(intfildes2);pipe調(diào)用可以創(chuàng)建一個管道(通信緩沖區(qū)).當調(diào)用成功時,我們可以訪問文件描述符fildes0,fildes1.其中fildes0是用來讀的文件描述符,而fildes1是用來寫的文件描述符.在實際使用中我們是通過創(chuàng)建一個子

57、進程,然后一個進程寫,一個進程讀來使用的.關(guān)于進程通信的詳細情況請查看進程通信#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<string.h>#include<errno.h>#include<sys/types.h>#include<sys/wait.h>#defineBUFFER255intmain(intargc,char*argv)(charbufferBUFFER+1;intfd2;if(argc!=2)(fprintf(s

58、tderr,"Usage:%sstringna",argv0);exit(1);if(pipe(fd)!=0)(fprintf(stderr,"PipeError:%sna",strerror(errno);exit(1);if(fork()=0)(close(fd0);printf("Child%dWritetopipena",getpid();snprintf(buffer,BUFFER,"%s",argv1);write(fd1,buffer,strlen(buffer);printf("Child%dQuitna",getpid();exit(0);else(close(fd1);printf("Parent%dReadfrompipena",getpid();memset(buffer,''0',BUFFER+1);read(fd0,buffer,BUFFER);printf("Parent%dRead:%sn",getpid(),buffe

溫馨提示

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

評論

0/150

提交評論