![《通信嵌入式系統(tǒng)技術(shù)與應(yīng)用》 課件 第3講 Linux 編程1_第1頁](http://file4.renrendoc.com/view4/M00/21/13/wKhkGGZfDVSAACI6AADVapgtZyU642.jpg)
![《通信嵌入式系統(tǒng)技術(shù)與應(yīng)用》 課件 第3講 Linux 編程1_第2頁](http://file4.renrendoc.com/view4/M00/21/13/wKhkGGZfDVSAACI6AADVapgtZyU6422.jpg)
![《通信嵌入式系統(tǒng)技術(shù)與應(yīng)用》 課件 第3講 Linux 編程1_第3頁](http://file4.renrendoc.com/view4/M00/21/13/wKhkGGZfDVSAACI6AADVapgtZyU6423.jpg)
![《通信嵌入式系統(tǒng)技術(shù)與應(yīng)用》 課件 第3講 Linux 編程1_第4頁](http://file4.renrendoc.com/view4/M00/21/13/wKhkGGZfDVSAACI6AADVapgtZyU6424.jpg)
![《通信嵌入式系統(tǒng)技術(shù)與應(yīng)用》 課件 第3講 Linux 編程1_第5頁](http://file4.renrendoc.com/view4/M00/21/13/wKhkGGZfDVSAACI6AADVapgtZyU6425.jpg)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第3講Linux編程(1)3.1Linux下C語言編程概述3.2Linux編程初步實(shí)驗(yàn)二Linux下的C/C++語言編程實(shí)驗(yàn)三Linux編程初步第三章Linux編程3.1
Linux下C語言編程概述
1、C語言簡(jiǎn)單回顧
2、Linux下C語言編程環(huán)境概述3、Gcc/g++編譯器4、Gdb調(diào)試器5、Make工程管理器6、使用autotools1、C語言簡(jiǎn)單回顧C(jī)語言最早是由貝爾實(shí)驗(yàn)室的DennisRitchie為了UNIX的輔助開發(fā)而編寫的,它是在B語言的基礎(chǔ)上開發(fā)出來的。由于它的硬件無關(guān)性和可移植性,使C語言逐漸成為世界上使用最廣泛計(jì)算機(jī)語言。為了進(jìn)一步規(guī)范C語言的硬件無關(guān)性,1987年,美國國家標(biāo)準(zhǔn)協(xié)會(huì)(ANSI)根據(jù)C語言問世以來各種版本對(duì)C語言的發(fā)展和擴(kuò)充,制定了新的標(biāo)準(zhǔn),稱為ANSIC。目前流行的C語言編譯系統(tǒng)都是以它為基礎(chǔ)的。2.Linux下C語言編程環(huán)境概述Linux下的C語言程序設(shè)計(jì)與在其他環(huán)境中的C程序設(shè)計(jì)一樣,主要涉及到編輯器、編譯鏈接器、調(diào)試器及項(xiàng)目管理工具。(1)編輯器Linux下的編輯器就如Windows下的word、記事本等一樣,完成對(duì)所錄入文字的編輯功能。Linux中最常用的編輯器有Vi(Vim)和gedit,它們功能強(qiáng)大,使用方便,廣受編程愛好者的喜愛。(2)編譯鏈接器編譯是指源代碼轉(zhuǎn)化生成可執(zhí)行代碼的過程。編譯過程包括:詞法、語法和語義的分析、中間代碼的生成和優(yōu)化、符號(hào)表的管理和出錯(cuò)處理等。在Linux中,編譯C語言程序最常用的編譯器是Gcc編譯器,它是GNU推出的功能強(qiáng)大、性能優(yōu)越的多平臺(tái)編譯器。注:g++編譯器可用來編譯鏈接c++程序。(3)調(diào)試器調(diào)試器是專為程序員方便調(diào)試程序而用的。在編程的過程當(dāng)中,往往調(diào)試所消耗的時(shí)間遠(yuǎn)遠(yuǎn)大于編寫代碼的時(shí)間。因此,有一個(gè)功能強(qiáng)大、使用方便的調(diào)試器是必不可少的。Gdb是絕大多數(shù)Linux開發(fā)人員所使用的調(diào)試器,它可以方便地設(shè)置斷點(diǎn)、單步跟蹤等,足以滿足開發(fā)人員的需要。(4)項(xiàng)目管理器Linux中的項(xiàng)目管理器make有些類似于Windows中VisualC++里的“工程”,它是一種控制編譯或者重復(fù)編譯軟件的工具,另外,它還能自動(dòng)管理軟件編譯的內(nèi)容、方式和時(shí)機(jī),使程序員能夠把精力集中在代碼的編寫上而不是在源代碼的組織上。2、Gcc編譯器GNUCC(簡(jiǎn)稱為Gcc)是GNU項(xiàng)目中符合ANSIC標(biāo)準(zhǔn)的編譯系統(tǒng),能夠編譯用C、C++和ObjectC等語言編寫的程序。Gcc不僅功能強(qiáng)大,而且可以編譯如C、C++、ObjectC、Java、Fortran、Pascal、Modula-3和Ada等多種語言,而且Gcc又是一個(gè)交叉平臺(tái)編譯器,它能夠在當(dāng)前CPU平臺(tái)上為多種不同體系結(jié)構(gòu)的硬件平臺(tái)開發(fā)軟件,因此尤其適合在嵌入式領(lǐng)域的開發(fā)編譯。(1)Gcc編譯流程解析Gcc的編譯流程分為了4個(gè)步驟,分別為:[1]預(yù)處理(Pre-Processing)
.i[2]編譯(Compiling).s[3]匯編(Assembling).o[4]鏈接(Linking)可執(zhí)行文件./編譯鏈接過程框圖:例1hello.c源代碼:(用gedit編寫)#include<stdio.h>main(){ printf("Hello,world!\n");}輸入:gedithelloworld.c,出現(xiàn):<1>預(yù)處理階段編譯器將上述代碼中的stdio.h編譯進(jìn)來,并且用戶可以使用Gcc的選項(xiàng)“-E”進(jìn)行查看,該選項(xiàng)的作用是讓Gcc在預(yù)處理結(jié)束后停止編譯過程。Gcc指令的一般格式為:gcc[選項(xiàng)]要編譯的文件[選項(xiàng)][目標(biāo)文件]其中,目標(biāo)文件可缺省,Gcc默認(rèn)生成可執(zhí)行的文件,名為:編譯文件.out輸入:gcc-Ehello.c-ohello.i“-o”是目標(biāo)文件,hello.i
是經(jīng)過預(yù)處理的C原始程序。<2>編譯階段在這個(gè)階段中,Gcc首先要檢查代碼的規(guī)范性、是否有語法錯(cuò)誤等,以確定代碼的實(shí)際要做的工作,在檢查無誤后,Gcc把代碼翻譯成匯編語言。用戶可以使用“-S”選項(xiàng)來進(jìn)行查看,該選項(xiàng)只進(jìn)行編譯而不進(jìn)行匯編,生成匯編代碼。
輸入:gcc–Shello.i–ohello.s<3>匯編階段匯編階段是把編譯階段生成的“.s”文件轉(zhuǎn)成目標(biāo)文件,讀者在此可使用選項(xiàng)“-c”就可看到匯編代碼已轉(zhuǎn)化為“.o”的二進(jìn)制目標(biāo)代碼了。
輸入:gcc-chello.s-ohello.o<4>鏈接階段在成功編譯之后,就進(jìn)入了鏈接階段。在這里涉及到一個(gè)重要的概念:函數(shù)庫。讀者可以重新查看這個(gè)小程序,在這個(gè)程序中并沒有定義“printf”的函數(shù)實(shí)現(xiàn),且在預(yù)編譯中包含進(jìn)的“stdio.h”中也只有該函數(shù)的聲明,而沒有定義函數(shù)的實(shí)現(xiàn),那么,是在哪里實(shí)現(xiàn)“printf”函數(shù)的呢?最后的答案是:系統(tǒng)把這些函數(shù)實(shí)現(xiàn)都被做到名為libc.so.6的庫文件中去了,在沒有特別指定時(shí),Gcc會(huì)到系統(tǒng)默認(rèn)的搜索路徑“/usr/lib”下進(jìn)行查找,也就是鏈接到libc.so.6庫函數(shù)中去,這樣就能實(shí)現(xiàn)函數(shù)“printf”了,而這也就是鏈接的作用。輸入:gcchello.o–ohello運(yùn)行該可執(zhí)行文件:(2)Gcc編譯選項(xiàng)分析(p55-58)Gcc有超過100個(gè)的可用選項(xiàng),主要包括總體選項(xiàng)、告警和出錯(cuò)選項(xiàng)、優(yōu)化選項(xiàng)和體系結(jié)構(gòu)相關(guān)選項(xiàng)。<1>全局選項(xiàng)<2>告警和出錯(cuò)選項(xiàng)<3>優(yōu)化選項(xiàng)<4>體系結(jié)構(gòu)相關(guān)選項(xiàng)<1>全局選項(xiàng)后綴名所對(duì)應(yīng)的語言-c只是編譯不鏈接,生成目標(biāo)文件“.o”-S只是編譯不匯編,生成匯編代碼-E只進(jìn)行預(yù)編譯,不做其他處理-g在可執(zhí)行程序中包含標(biāo)準(zhǔn)調(diào)試信息-ofile把輸出文件輸出到file里-v打印出編譯器內(nèi)部編譯各過程的命令行信息和編譯器的版本-Idir在頭文件的搜索路徑列表中添加dir目錄-Ldir在庫文件的搜索路徑列表中添加dir目錄-static鏈接靜態(tài)庫-llibrary連接名為library的庫文件<2>告警和出錯(cuò)選項(xiàng)。選項(xiàng)含義-ansi支持符合ANSI標(biāo)準(zhǔn)的C程序-pedantic允許發(fā)出ANSIC標(biāo)準(zhǔn)所列的全部警告信息-pedantic-error允許發(fā)出ANSIC標(biāo)準(zhǔn)所列的全部錯(cuò)誤信息-w關(guān)閉所有告警-Wall允許發(fā)出Gcc提供的所有有用的報(bào)警信息-werror把所有的告警信息轉(zhuǎn)化為錯(cuò)誤信息,并在告警發(fā)生時(shí)終止編譯過程<3>優(yōu)化選項(xiàng)Gcc可以對(duì)代碼進(jìn)行優(yōu)化,它通過編譯選項(xiàng)“-On”來控制優(yōu)化代碼的生成,其中n是一個(gè)代表優(yōu)化級(jí)別的整數(shù)。對(duì)于不同版本的Gcc來講,n的取值范圍及其對(duì)應(yīng)的優(yōu)化效果可能并不完全相同,比較典型的范圍是從0變化到2或3。不同的優(yōu)化級(jí)別對(duì)應(yīng)不同的優(yōu)化處理工作。如使用優(yōu)化選項(xiàng)“-O”主要進(jìn)行線程跳轉(zhuǎn)(ThreadJump)和延遲退棧(DeferredStackPops)兩種優(yōu)化。使用優(yōu)化選項(xiàng)“-O2”除了完成所有“-O1”級(jí)別的優(yōu)化之外,同時(shí)還要進(jìn)行一些額外的調(diào)整工作,如處理器指令調(diào)度等。選項(xiàng)“-O3”則還包括循環(huán)展開和其他一些與處理器特性相關(guān)的優(yōu)化工作。雖然優(yōu)化選項(xiàng)可以加速代碼的運(yùn)行速度,但對(duì)于調(diào)試而言將是一個(gè)很大的挑戰(zhàn)。因?yàn)榇a在經(jīng)過優(yōu)化之后,原先在源程序中聲明和使用的變量很可能不再使用,控制流也可能會(huì)突然跳轉(zhuǎn)到意外的地方,循環(huán)語句也有可能因?yàn)檠h(huán)展開而變得到處都有,所有這些對(duì)調(diào)試來講都將是一場(chǎng)噩夢(mèng)。建議:在調(diào)試的時(shí)候最好不使用任何優(yōu)化選項(xiàng),只有當(dāng)程序在最終發(fā)行的時(shí)候才考慮對(duì)其進(jìn)行優(yōu)化。<4>體系結(jié)構(gòu)相關(guān)選項(xiàng)選項(xiàng)含義-mcpu=type針對(duì)不同的CPU使用相應(yīng)的CPU指令??蛇x擇的type有i386、i486、pentium及i686等-mieee-fp使用IEEE標(biāo)準(zhǔn)進(jìn)行浮點(diǎn)數(shù)的比較-mno-ieee-fp不使用IEEE標(biāo)準(zhǔn)進(jìn)行浮點(diǎn)數(shù)的比較-msoft-float輸出包含浮點(diǎn)庫調(diào)用的目標(biāo)代碼-mshort把int類型作為16位處理,相當(dāng)于shortint-mrtd強(qiáng)行將函數(shù)參數(shù)個(gè)數(shù)固定的函數(shù)用retNUM返回,節(jié)省調(diào)用函數(shù)的一條指令3、Gdb調(diào)試器Gdb調(diào)試器:是一款GNU開發(fā)組織并發(fā)布的UNIX/Linux下的程序調(diào)試工具。雖然,它沒有圖形化的友好界面,但是它強(qiáng)大的功能也足以與微軟的VC工具等媲美。3、Gdb調(diào)試器Gdb使用流程Gdb基本命令Gdb中源碼查看相關(guān)命令Gdb中查看運(yùn)行數(shù)據(jù)相關(guān)命令Gdb中修改運(yùn)行參數(shù)相關(guān)命令3、Gdb調(diào)試器Gdb使用流程<1>查看文件<2>設(shè)置斷點(diǎn)<3>查看斷點(diǎn)情況<4>運(yùn)行代碼<5>查看變量值<6>單步運(yùn)行<7>恢復(fù)程序運(yùn)行3、Gdb調(diào)試器(2)Gdb基本命令<1>工作環(huán)境相關(guān)命令命令格式含義setargs運(yùn)行時(shí)的參數(shù)指定運(yùn)行時(shí)參數(shù),如setargs2showargs查看設(shè)置好的運(yùn)行參數(shù)pathdir設(shè)定程序的運(yùn)行路徑showpaths查看程序的運(yùn)行路徑setenVironmentvar[=value]設(shè)置環(huán)境變量showenVironment[var]查看環(huán)境變量cddir進(jìn)入到dir目錄,相當(dāng)于shell中的cd命令pwd顯示當(dāng)前工作目錄shellcommand運(yùn)行shell的command命令3、Gdb調(diào)試器(2)Gdb基本命令<2>設(shè)置斷點(diǎn)與恢復(fù)命令命令格式含義bnfob查看所設(shè)斷點(diǎn)break行號(hào)或函數(shù)名<條件表達(dá)式>設(shè)置斷點(diǎn)tbreak行號(hào)或函數(shù)名<條件表達(dá)式>設(shè)置臨時(shí)斷點(diǎn),到達(dá)后被自動(dòng)刪除delete[斷點(diǎn)號(hào)]刪除指定斷點(diǎn),其斷點(diǎn)號(hào)為“infob”中的第一欄。若缺省斷點(diǎn)號(hào)則刪除所有斷點(diǎn)disable[斷點(diǎn)號(hào)]]停止指定斷點(diǎn),使用“infob”仍能查看此斷點(diǎn)。同delete一樣,省斷點(diǎn)號(hào)則停止所有斷點(diǎn)enable[斷點(diǎn)號(hào)]激活指定斷點(diǎn),即激活被disable停止的斷點(diǎn)condition[斷點(diǎn)號(hào)]<條件表達(dá)式>修改對(duì)應(yīng)斷點(diǎn)的條件ignore[斷點(diǎn)號(hào)]<num>在程序執(zhí)行中,忽略對(duì)應(yīng)斷點(diǎn)num次step單步恢復(fù)程序運(yùn)行,且進(jìn)入函數(shù)調(diào)用next單步恢復(fù)程序運(yùn)行,但不進(jìn)入函數(shù)調(diào)用finish運(yùn)行程序,直到當(dāng)前函數(shù)完成返回c繼續(xù)執(zhí)行函數(shù),直到函數(shù)結(jié)束或遇到新的斷點(diǎn)3、Gdb調(diào)試器(3)Gdb中源碼查看相關(guān)命令在Gdb中可以查看源碼以方便其他操作,它的常見相關(guān)命令如下表所示。命令格式含義list<行號(hào)>|<函數(shù)名>查看指定位置代碼file[文件名]加載指定文件forward-search正則表達(dá)式源代碼前向搜索reverse-search正則表達(dá)式源代碼后向搜索dirdir停止路徑名showdirectories顯示定義了的源文件搜索路徑infoline顯示加載到Gdb內(nèi)存中的代碼3、Gdb調(diào)試器(4)Gdb中查看運(yùn)行數(shù)據(jù)相關(guān)Gdb中查看運(yùn)行數(shù)據(jù)是指當(dāng)程序處于“運(yùn)行”或“暫停”狀態(tài)時(shí),可以查看的變量及表達(dá)式的信息,其常見命令如表所示命令格式含義print表達(dá)式|變量查看程序運(yùn)行時(shí)對(duì)應(yīng)表達(dá)式和變量的值x<n/f/u>查看內(nèi)存變量內(nèi)容。其中n為整數(shù)表示顯示內(nèi)存的長度,f表示顯示的格式,u表示從當(dāng)前地址往后請(qǐng)求顯示的字節(jié)數(shù)display表達(dá)式設(shè)定在單步運(yùn)行或其他情況中,自動(dòng)顯示的對(duì)應(yīng)表達(dá)式的內(nèi)容3、Gdb調(diào)試器(5)Gdb中修改運(yùn)行參數(shù)相關(guān)命令Gdb還可以修改運(yùn)行時(shí)的參數(shù),并使該變量按照用戶當(dāng)前輸入的值繼續(xù)運(yùn)行。它的設(shè)置方法為:在單步執(zhí)行的過程中,鍵入命令“set變量=設(shè)定值”。這樣,在此之后,程序就會(huì)按照該設(shè)定的值運(yùn)行。下面,筆者結(jié)合上一節(jié)的代碼將n的初始值設(shè)為4,其代碼如下所示(Gdb)b7Breakpoint5at0x804847a:filetest.c,line7.(Gdb)rStartingprogram:/home/yul/testThesumof1-mis1275Breakpoint5,main()attest.c:77for(i=1;i<=50;i++)(Gdb)setn=4(Gdb)cContinuing.Thesumof1-50is1279Programexitedwithcode031.4、Make工程管理器工程管理器:可看做是一個(gè)自動(dòng)編譯管理器,可管理較多文件。
有一個(gè)上百個(gè)文件的代碼構(gòu)成的項(xiàng)目,如果其中只有一個(gè)或少數(shù)幾個(gè)文件進(jìn)行了修改,按照之前所學(xué)的Gcc編譯工具,就不得不把這所有的文件重新編譯一遍,費(fèi)時(shí)費(fèi)力。Make能夠根據(jù)文件時(shí)間戳自動(dòng)發(fā)現(xiàn)更新過的文件而減少編譯的工作量,同時(shí),它通過讀入Makefile文件的內(nèi)容來執(zhí)行大量的編譯工作,用戶只需編寫一次簡(jiǎn)單的編譯語句就可以了。它大大提高了實(shí)際項(xiàng)目的工作效率。4、Make工程管理器Makefile基本結(jié)構(gòu)Makefile變量Makefile規(guī)則Make管理器的使用4、Make工程管理器Makefile基本結(jié)構(gòu)Makefile:是Make讀入的惟一配置文件Makefile的編寫規(guī)則:--在一個(gè)Makefile中通常包含如下內(nèi)容:1)需要由make工具創(chuàng)建的目標(biāo)體(target),通常是目標(biāo)文件或可執(zhí)行文件;2)要?jiǎng)?chuàng)建的目標(biāo)體所依賴的文件;(dependency_file)3)創(chuàng)建每個(gè)目標(biāo)體時(shí)需要運(yùn)行的命令;(command)Makefile格式:target:dependency_filescommand例1有兩個(gè)文件分別為hello.c和hello.h,創(chuàng)建的目標(biāo)體為hello.o,執(zhí)行的命令為gcc編譯指令:gcc–chello.c,那么,對(duì)應(yīng)的Makefile就可以寫為:#Thesimplestexamplehello.o:hello.chello.hgcc–chello.c–ohello.o其中:hello.c是:#include"hello.h"intmain(){printf("Helloworld!\n");}hello.h是:#include<stdio.h>接著就可以使用make了。使用make的格式為:maketarget,這樣make就會(huì)自動(dòng)讀入Makefile(也可以是首字母小寫makefile)并執(zhí)行對(duì)應(yīng)target的command語句,并會(huì)找到相應(yīng)的依賴文件。[davinci@davinci-desktop]#makehello.ogcc–chello.c–ohello.o[davinci@davinci-desktop]#lshello.c
hello.h
hello.o
Makefile可以看到,Makefile執(zhí)行了“hello.o”對(duì)應(yīng)的命令語句,并生成了“hello.o”目標(biāo)體。Makefile(用gedit編寫)的內(nèi)容是:注意:在Makefile中的每一個(gè)command前必須有“Tab”符,否則在運(yùn)行make命令時(shí)會(huì)出錯(cuò)。4、Make工程管理器(2)Makefile變量
上面示例的Makefile在實(shí)際中是幾乎不存在的,因?yàn)樗^于簡(jiǎn)單,僅包含兩個(gè)文件和一個(gè)命令,在這種情況下完全不必要編寫Makefile,而只需在Shell中直接輸入即可。
在實(shí)際中使用的Makefile往往是包含很多的文件和命令的,這也是Makefile產(chǎn)生的原因。下面就可給出稍微復(fù)雜一些的Makefile進(jìn)行講解:sunq:kang.oyul.oGcckang.obar.o-omyprogkang.o:kang.ckang.hhead.hGcc–Wall–O-g–ckang.c-okang.oyul.o:bar.chead.hGcc-Wall–O-g–cyul.c-oyul.o例2在這個(gè)Makefile中有3個(gè)目標(biāo)體(target),分別為sunq、kang.o和yul.o,其中第一個(gè)目標(biāo)體的依賴文件就是后兩個(gè)目標(biāo)體。
如果用戶使用命令“makesunq”,則make管理器就是找到sunq目標(biāo)體開始執(zhí)行。這時(shí),make會(huì)自動(dòng)檢查相關(guān)文件的時(shí)間戳。首先,在檢查“kang.o”、“yul.o”和“sunq”3個(gè)文件的時(shí)間戳之前,它會(huì)向下查找那些把“kang.o”或“yul.o”作為目標(biāo)文件的時(shí)間戳。比如,“kang.o”的依賴文件為“kang.c”、“kang.h”、“head.h”。如果這些文件中任何一個(gè)的時(shí)間戳比“kang.o”新,則命令“gcc–Wall–O-g–ckang.c-okang.o”將會(huì)執(zhí)行,從而更新文件“kang.o”。在更新完“kang.o”或“yul.o”之后,make會(huì)檢查最初的“kang.o”、“yul.o”和“sunq”3個(gè)文件,只要文件“kang.o”或“yul.o”中的任比文件時(shí)間戳比“sunq”新,則第二行命令就會(huì)被執(zhí)行。這樣,make就完成了自動(dòng)檢查時(shí)間戳的工作,開始執(zhí)行編譯工作。這就是Make工作的基本流程。為了進(jìn)一步簡(jiǎn)化編輯和維護(hù)Makefile,make允許在Makefile中創(chuàng)建和使用變量。變量:在Makefile中定義的名字,用來代替一個(gè)文本字符串,該文本字符串稱為該變量的值。在具體要求下,這些值可以代替目標(biāo)體、依賴文件、命令以及makefile文件中其他部分。在Makefile中的變量定義有兩種方式:一種是遞歸展開方式,另一種是簡(jiǎn)單方式。*遞歸展開方式定義的變量是在引用在該變量時(shí)進(jìn)行替換的,即:如果該變量包含了對(duì)其他變量的應(yīng)用,則在引用該變量時(shí)一次性將內(nèi)嵌的變量全部展開;缺點(diǎn)如:不能在變量后追加內(nèi)容。*簡(jiǎn)單擴(kuò)展型變量的值在定義處展開,并且只展開一次,因此它不包含任何對(duì)其他變量的引用,從而消除變量的嵌套引用。遞歸展開方式的定義格式為:VAR=var。簡(jiǎn)單擴(kuò)展方式的定義格式為:VAR:=var。Make中的變量使用均使用格式為:$(VAR)。注意:變量名是不包括“:”、“#”、“=”結(jié)尾空格的任何字符串。同時(shí),變量名中包含字母、數(shù)字以及下劃線以外的情況應(yīng)盡量避免,因?yàn)樗鼈兛赡茉趯肀毁x予特別的含義。變量名是大小寫敏感的,例如變量名“foo”、“FOO”、和“Foo”代表不同的變量。推薦在makefile內(nèi)部使用小寫字母作為變量名,預(yù)留大寫字母作為控制隱含規(guī)則參數(shù)或用戶重載命令選項(xiàng)參數(shù)的變量名。經(jīng)變量替換后的Makefile如下所示:
OBJS=kang.oyul.oCC=GccCFLAGS=-Wall-O-gsunq:$(OBJS)$(CC)$(OBJS)-osunqkang.o:kang.ckang.h$(CC)$(CFLAGS)-ckang.c-okang.oyul.o:yul.cyul.h$(CC)$(CFLAGS)-cyul.c-oyul.o可以看到,此處變量是以遞歸展開方式定義的。這里:用OBJS代替kang.o和yul.o,用CC代替Gcc,用CFLAGS代替“-Wall-O–g”。這樣在以后修改時(shí),就可以只修改變量定義,而不需要修改下面的定義實(shí)體,從而大大簡(jiǎn)化了Makefile維護(hù)的工作量。Makefile中的變量分為:用戶自定義變量、預(yù)定義變量、自動(dòng)變量及環(huán)境變量。如上例中的OBJS就是用戶自定義變量,自定義變量的值由用戶自行設(shè)定,而預(yù)定義變量和自動(dòng)變量為通常在Makefile都會(huì)出現(xiàn)的變量,其中部分有默認(rèn)值,也就是常見的設(shè)定值,當(dāng)然用戶可以對(duì)其進(jìn)行修改。預(yù)定義變量包含了常見編譯器、匯編器的名稱及其編譯選項(xiàng)。可以看出,上例中的CC和CFLAGS是預(yù)定義變量,其中由于CC沒有采用默認(rèn)值,因此,需要把“CC=Gcc”明確列出來。由于常見的Gcc編譯語句中通常包含了目標(biāo)文件和依賴文件,而這些文件在Makefile文件中目標(biāo)體的一行已經(jīng)有所體現(xiàn),因此,為了進(jìn)一步簡(jiǎn)化Makefile的編寫,就引入了自動(dòng)變量。自動(dòng)變量通??梢源砭幾g語句中出現(xiàn)目標(biāo)文件和依賴文件等,并且具有本地含義(即下一語句中出現(xiàn)的相同變量代表的是下一語句的目標(biāo)文件和依賴文件)。自動(dòng)變量的書寫比較難記,但是在熟練了之后會(huì)非常的方便,下例是前面一個(gè)例子用自動(dòng)變量改寫的Makefile:OBJS=kang.oyul.oCC=GccCFLAGS=-Wall-O-gsunq:$(OBJS)$(CC)$^-o$@kang.o:kang.ckang.h$(CC)$(CFLAGS)-c$<-o$@yul.o:yul.cyul.h$(CC)$(CFLAGS)-c$<-o$@另外,在Makefile中還可以使用環(huán)境變量。使用環(huán)境變量的方法相對(duì)比較簡(jiǎn)單,make在啟動(dòng)時(shí)會(huì)自動(dòng)讀取系統(tǒng)當(dāng)前已經(jīng)定義了的環(huán)境變量,并且會(huì)創(chuàng)建與之具有相同名稱和數(shù)值的變量。但是,如果用戶在Makefile中定義了相同名稱的變量,那么用戶自定義變量將會(huì)覆蓋同名的環(huán)境變量。4、Make工程管理器(3)Makefile規(guī)則Makefile的規(guī)則是:Make進(jìn)行處理的依據(jù),它包括了目標(biāo)體、依賴文件及其之間的命令語句。Makefile中的一條語句就是一個(gè)規(guī)則。在上面的例子中,都顯示地指出了Makefile中的規(guī)則關(guān)系,如“$(CC)$(CFLAGS)-c$<-o$@”,為了簡(jiǎn)化Makefile的編寫,make還定義了隱式規(guī)則和模式規(guī)則:<1>隱式規(guī)則隱含規(guī)則能夠告訴make怎樣使用傳統(tǒng)的技術(shù)完成任務(wù),這樣,當(dāng)用戶使用它們時(shí)就不必詳細(xì)指定編譯的具體細(xì)節(jié),而只需把目標(biāo)文件列出即可。Make會(huì)自動(dòng)搜索隱式規(guī)則目錄來確定如何生成目標(biāo)文件。上例可寫成:OBJS=kang.oyul.oCC=GccCFLAGS=-Wall-O-gsunq:$(OBJS)$(CC)$^-o$@為什么可以省略后兩句呢?因?yàn)镸ake的隱式規(guī)則指出:所有“.o”文件都可自動(dòng)由“.c”文件使用命令“$(CC)$(CPPFLAGS)$(CFLAGS)-cfile.c–ofile.o”生成。這樣“kang.o”和“yul.o”就會(huì)分別調(diào)用“$(CC)$(CFLAGS)-ckang.c-okang.o”和“$(CC)$(CFLAGS)-cyul.c-oyul.o”生成。<2>模式規(guī)則模式規(guī)則是用來定義相同處理規(guī)則的多個(gè)文件的。它不同于隱式規(guī)則,隱式規(guī)則僅僅能夠用make默認(rèn)的變量來進(jìn)行操作,而模式規(guī)則還能引入用戶自定義變量,為多個(gè)文件建立相同的規(guī)則,從而進(jìn)一步簡(jiǎn)化Makefile的編寫。模式規(guī)則的格式類似于普通規(guī)則,這個(gè)規(guī)則中的相關(guān)文件前必須用“%”標(biāo)明。
使用模式規(guī)則修改后的Makefile的編寫如下:
OBJS=kang.oyul.oCC=GccCFLAGS=-Wall-O-gsunq:$(OBJS)$(CC)$^-o$@%.o:%.c$(CC)$(CFLAGS)-c$<-o$@4、Make工程管理器(4)Make管理器的使用使用Make管理器只需在make命令的后面鍵入目標(biāo)名即可建立指定的目標(biāo),如果直接運(yùn)行make,則建立Makefile中的第一個(gè)目標(biāo)。此外make還有豐富的命令行選項(xiàng),可以完成各種不同的功能。下表列出了常用的make命令行選項(xiàng)。5、使用autotools有沒有一種輕松的手段生成Makefile而同時(shí)又能讓用戶享受make的優(yōu)越性呢?本節(jié)要講的autotools系列工具正是為此而設(shè)的,它只需用戶輸入簡(jiǎn)單的目標(biāo)文件、依賴文件、文件目錄等就可以輕松地生成Makefile了,這無疑是廣大用戶的所希望的。另外,這些工具還可以完成系統(tǒng)配置信息的收集,從而可以方便地處理各種移植性的問題。也正是基于此,現(xiàn)在Linux上的軟件開發(fā)一般都用autotools來制作Makefile。5、使用autotools(1)autotools使用流程<1>autoscan<2>autoconf<3>autoheader<4>automake<5>運(yùn)行configure使用autotools所生成的Makefile<1>make<2>makeinstall<3>makeclean<4>makedist<1>autoscan<1>autoscan它會(huì)在給定目錄及其子目錄樹中檢查源文件,若沒有給出目錄,就在當(dāng)前目錄及其子目錄樹中進(jìn)行檢查。它會(huì)搜索源文件以尋找一般的移植性問題并創(chuàng)建一個(gè)文件“configure.scan”,該文件就是接下來autoconf要用到的“configure.in”原型。它會(huì)自動(dòng)生成一個(gè)“configure.in”的原型文件configure.scan”。Configure.scan內(nèi)容:<2>autoconf
configure.in是autoconf的腳本配置文件。以“#”號(hào)開始的行為注釋。AC_PREREQ宏聲明本文件要求的autoconf版本,如本例使用的版本2.59AC_INIT宏用來定義軟件的名稱和版本等信息,在本例中省略了BUG-REPORT-ADDRESS,一般為作者的E-mailAM_INIT_AUTOMAKE是筆者另加的,它是automake所必備的宏,也同前面一樣,PACKAGE是所要產(chǎn)生軟件套件的名稱,VERSION是版本編號(hào)AC_CONFIG_SRCDIR宏用來偵測(cè)所指定的源碼文件是否存在,來確定源碼目錄的有效性。在此處為當(dāng)前目錄下的hello.cAC_CONFIG_HEADER宏用于生成config.h文件,以便autoheader使用AC_CONFIG_FILES宏用于生成相應(yīng)的Makefile文件中間的注釋間可以添加分別用戶測(cè)試程序、測(cè)試函數(shù)庫、測(cè)試頭文件等宏定義。二、
Linux編程初步
1、Linux系統(tǒng)調(diào)用及用戶編程接口(API)
2、Linux中文件及文件描述符概述3、不帶緩存的文件I/O操作4、嵌入式Linux串口應(yīng)用開發(fā)5、標(biāo)準(zhǔn)I/O開發(fā)1、Linux系統(tǒng)調(diào)用及用戶編程接口(API)系統(tǒng)調(diào)用用戶編程接口(API)系統(tǒng)命令1、Linux系統(tǒng)調(diào)用及用戶編程接口(API)系統(tǒng)調(diào)用-----操作系統(tǒng)提供給用戶程序調(diào)用的一組“特殊”接口,用戶程序可以通過這組“特殊”接口來獲得操作系統(tǒng)內(nèi)核提供的服務(wù)。
例如用戶可以通過進(jìn)程控制相關(guān)的系統(tǒng)調(diào)用來創(chuàng)建進(jìn)程、實(shí)現(xiàn)進(jìn)程調(diào)度、進(jìn)程管理等。為什么用戶程序不能直接訪問系統(tǒng)內(nèi)核提供的服務(wù)呢?這是由于在Linux中,為了更好地保護(hù)內(nèi)核空間,將程序的運(yùn)行空間分為內(nèi)核空間和用戶空間(內(nèi)核態(tài)和用戶態(tài)),它們分別運(yùn)行在不同的級(jí)別上,在邏輯上是相互隔離的。因此,用戶進(jìn)程在通常情況下不允許訪問內(nèi)核數(shù)據(jù),也無法使用內(nèi)核函數(shù),它們只能在用戶空間操作用戶數(shù)據(jù),調(diào)用用戶空間的函數(shù)。1、Linux系統(tǒng)調(diào)用及用戶編程接口(API)(2)用戶編程接口(API)
系統(tǒng)調(diào)用并不是直接與程序員進(jìn)行交互的,它僅僅是一個(gè)通過軟中斷機(jī)制向內(nèi)核提交請(qǐng)求,以獲取內(nèi)核服務(wù)的接口。在實(shí)際使用中程序員調(diào)用的通常是用戶編程接口——API,也就是本書后面要講到的API函數(shù)。但并不是所有的函數(shù)都一一對(duì)應(yīng)一個(gè)系統(tǒng)調(diào)用。有時(shí),一個(gè)API函數(shù)會(huì)需要幾個(gè)系統(tǒng)調(diào)用來共同完成函數(shù)的功能,甚至還有一些API函數(shù)不需要調(diào)用相應(yīng)的系統(tǒng)調(diào)用(因此它所完成的不是內(nèi)核提供的服務(wù))。在Linux中,用戶編程接口(API)遵循了在UNIX中最流行的應(yīng)用編程界面標(biāo)準(zhǔn)——POSIX標(biāo)準(zhǔn)。POSIX標(biāo)準(zhǔn)是由IEEE和ISO/IEC共同開發(fā)的標(biāo)準(zhǔn)系統(tǒng)。該標(biāo)準(zhǔn)基于當(dāng)時(shí)現(xiàn)有的UNIX實(shí)踐和經(jīng)驗(yàn),描述了操作系統(tǒng)的系統(tǒng)調(diào)用編程接口(實(shí)際上就是API),用于保證應(yīng)用程序可以在源代碼一級(jí)上在多種操作系統(tǒng)上移植運(yùn)行。這些系統(tǒng)調(diào)用編程接口主要是通過C庫(libc)實(shí)現(xiàn)的。1、Linux系統(tǒng)調(diào)用及用戶編程接口(API)(3)系統(tǒng)命令系統(tǒng)命令相對(duì)API更高了一層,它實(shí)際上一個(gè)可執(zhí)行程序,它的內(nèi)部引用了用戶編程接口(API)來實(shí)現(xiàn)相應(yīng)的功能。它們之間的關(guān)系如下圖所示。2、Linux中文件及文件描述符概述在Linux中對(duì)目錄和設(shè)備的操作都等同于文件的操作,因此,大大簡(jiǎn)化了系統(tǒng)對(duì)不同設(shè)備的處理,提高了效率。Linux中的文件主要分為4種:普通文件、目錄文件、鏈接文件和設(shè)備文件。
那么,內(nèi)核如何區(qū)分和引用特定的文件呢?——文件描述符。對(duì)于Linux而言,所有對(duì)設(shè)備和文件的操作都使用文件描述符來進(jìn)行的。
文件描述符是一個(gè)非負(fù)的整數(shù),它是一個(gè)索引值,并指向內(nèi)核中每個(gè)進(jìn)程打開文件的記錄表。
當(dāng)打開一個(gè)現(xiàn)存文件或創(chuàng)建一個(gè)新文件時(shí),內(nèi)核就向進(jìn)程返回一個(gè)文件描述符;當(dāng)需要讀寫文件時(shí),也需要把文件描述符作為參數(shù)傳遞給相應(yīng)的函數(shù)。通常,一個(gè)進(jìn)程啟動(dòng)時(shí),都會(huì)打開3個(gè)文件:標(biāo)準(zhǔn)輸入、標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)出錯(cuò)處理。這3個(gè)文件分別對(duì)應(yīng)文件描述符為0、1和2(也就是宏替換STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO)3、不帶緩存的文件I/O操作本節(jié)主要介紹不帶緩存的文件I/O操作,主要用到5個(gè)函數(shù):open、read、write、lseek和close。不帶緩存是指每一個(gè)函數(shù)都只調(diào)用系統(tǒng)中的一個(gè)函數(shù)。這些函數(shù)雖然不是ANSIC的組成部分,但是是POSIX的組成部分。(1)open和close(2)read、write和lseek(3)
fcntl和lock(4)select3、不帶緩存的文件I/O操作open和close<1>open和close函數(shù)說明open函數(shù)是用于打開或創(chuàng)建文件,在打開或創(chuàng)建文件時(shí)可以指定文件的屬性及用戶的權(quán)限等各種參數(shù)。close函數(shù)是用于關(guān)閉一個(gè)打開的文件。當(dāng)一個(gè)進(jìn)程終止時(shí),它所有已打開的文件都由內(nèi)核自動(dòng)關(guān)閉,很多程序都使用這一功能關(guān)閉一個(gè)文件。<2>open和close函數(shù)格式<3>open和close函數(shù)使用實(shí)例
下面實(shí)例中的open函數(shù)帶有3個(gè)flag參數(shù):O_CREAT、O_TRUNC和O_WRONLY,這樣就可以對(duì)不同的情況指定相應(yīng)的處理方法。另外,這里對(duì)該文件的權(quán)限設(shè)置為0600。/*open1.c*/(p77)/*open.c*/#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdlib.h>#include<stdio.h>intmain(void){intfd;//fd—文件描述符/*調(diào)用open函數(shù),以可讀寫的方式打開,注意選項(xiàng)可以用“|”符號(hào)連接*/if((fd=open("/tmp/hello.c",O_CREAT|O_TRUNC|O_WRONLY,0600))<0){perror("open:");exit(1);}else{printf("Openfile:hello.c%d\n",fd);}if(close(fd)<0)//關(guān)閉文件{perror(“close:”);//出錯(cuò)信息exit(1);}elseprintf("Closehello.c\n");exit(0);}編譯、鏈接,運(yùn)行open1.c經(jīng)過交叉編譯后,將文件下載到目標(biāo)板,則該可執(zhí)行文件運(yùn)行后就能在目錄/tmp下新建一個(gè)hello.c的文件,其權(quán)限為0600。注意:open函數(shù)返回的文件描述符一定是最小的未用文件描述符。由于一個(gè)進(jìn)程在啟動(dòng)時(shí)自動(dòng)打開了0、1、2三個(gè)文件描述符,因此,該文件運(yùn)行結(jié)果中返回的文件描述符為3。3、不帶緩存的文件I/O操作(2)read、write和lseek<1>read、write和lseek函數(shù)作用read函數(shù)是用于將指定的文件描述符中讀出數(shù)據(jù)。當(dāng)從終端設(shè)備文件中讀出數(shù)據(jù)時(shí),通常一次最多讀一行。write函數(shù)是用于向打開的文件寫數(shù)據(jù),寫操作從文件的當(dāng)前位移量處開始。若磁盤已滿或超出該文件的長度,則write函數(shù)返回失敗。lseek函數(shù)是用于在指定的文件描述符中將文件指針定位到相應(yīng)的位置。<2>read、write和lseek函數(shù)格式
(p78表3.15-3.17)<3>函數(shù)使用實(shí)例該示例程序:a)打開上一節(jié)中創(chuàng)建的文件,然后對(duì)此文件進(jìn)行讀寫操作(記得要將文件打開屬性改為可讀寫,將文件權(quán)限也做相應(yīng)更改)。b)寫入“Hello!I‘mwritingtothisfile!”,此時(shí)文件指針位于文件尾部。c)使用lseek函數(shù)將文件指針移到文件開始處,并讀出10個(gè)字節(jié)并將其打印出來。/*write.c*/#include<unistd.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include<stdlib.h>#include<stdio.h>#include<string.h>#defineMAXSIZEintmain(void){inti,fd,size,len;char*buf="Hello!I'mwritingtothisfile!";charbuf_r[10];
len=strlen(buf);//buf的長度/*首先調(diào)用open函數(shù),并指定相應(yīng)的權(quán)限*/if((fd=open("/tmp/hello.c",O_CREAT|O_TRUNC|O_RDWR,0666))<0){perror("open:");exit(1);}elseprintf("openfile:hello.c%d\n",fd);/*調(diào)用write函數(shù),將buf中的內(nèi)容寫入到打開的文件中*/if((size=write(fd,buf,len))<0){perror("write:");exit(1);}elseprintf("Write:%s\n",buf);/*調(diào)用lseek函數(shù)將文件指針移到文件起始,并讀出文件中的10個(gè)字節(jié)*/lseek(fd,0,SEEK_SET);if((size=read(fd,buf_r,10))<0){perror("read:");exit(1);}elseprintf("readformfile:%s\n",buf_r);if(close(fd)<0){perror("close:");exit(1);}elseprintf("Closehello.c\n");exit(0);}編譯、鏈接和運(yùn)行:write1.c3、不帶緩存的文件I/O操作(3)
fcntl---建立記錄鎖<1>fcntl函數(shù)說明當(dāng)多個(gè)用戶共同使用、操作一個(gè)文件的情況,這時(shí),Linux通常采用的方法是給文件上鎖,來避免共享的資源產(chǎn)生競(jìng)爭(zhēng)的狀態(tài)。文件鎖包括建議性鎖和強(qiáng)制性鎖。建議性鎖要求每個(gè)上鎖文件的進(jìn)程都要檢查是否有鎖存在,并且尊重已有的鎖。在一般情況下,內(nèi)核和系統(tǒng)都不使用建議性鎖。強(qiáng)制性鎖是由內(nèi)核執(zhí)行的鎖,當(dāng)一個(gè)文件被上鎖進(jìn)行寫入操作的時(shí)候,內(nèi)核將阻止其他任何文件對(duì)其進(jìn)行讀寫操作。采用強(qiáng)制性鎖對(duì)性能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。在Linux中,實(shí)現(xiàn)文件上鎖的函數(shù)有l(wèi)ock和fcntl,其中l(wèi)ock用于對(duì)文件施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強(qiáng)制鎖。同時(shí),fcntl還能對(duì)文件的某一記錄進(jìn)行上鎖,也就是記錄鎖。記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共享鎖,它能夠使多個(gè)進(jìn)程都能在文件的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時(shí)刻只能有一個(gè)進(jìn)程在文件的某個(gè)部分上建立寫入鎖。在文件的同一部分不能同時(shí)建立讀取鎖和寫入鎖。<2>fcntl函數(shù)格式(表3.18-3.19)<3>fcntl使用實(shí)例下面首先給出了使用fcntl函數(shù)的文件記錄鎖函數(shù)。在該函數(shù)中:a)給flock結(jié)構(gòu)體的對(duì)應(yīng)位賦予相應(yīng)的值。b)使用兩次fcntl函數(shù)分別用于給相關(guān)文件上鎖和判斷文件是否可以上鎖,這里用到的cmd值分別為F_SETLK和F_GETLK。/*lock_set函數(shù)*/voidlock_set(intfd,inttype){structflocklock;
lock.l_whence=SEEK_SET;//賦值lock結(jié)構(gòu)體lock.l_start=0;lock.l_len=0;while(1){lock.l_type=type;/*根據(jù)不同的type值給文件上鎖或解鎖*/if((fcntl(fd,F_SETLK,&lock))==0){if(lock.l_type==F_RDLCK)printf("readlocksetby%d\n",getpid());elseif(lock.l_type==F_WRLCK)printf("writelocksetby%d\n",getpid());elseif(lock.l_type==F_UNLCK)printf("releaselockby%d\n",getpid());return;}/*判斷文件是否可以上鎖*/fcntl(fd,F_GETLK,&lock);/*判斷文件不能上鎖的原因*/if(lock.l_type!=F_UNLCK){/*該文件已有寫入鎖*/if(lock.l_type==F_RDLCK)printf("readlockalreadysetby%d\n",lock.l_pid);/*該文件已有讀取鎖*/elseif(lock.l_type==F_WRLCK)printf("writelockalreadysetby%d\n",lock.l_pid);getchar();}}}下面的實(shí)例是測(cè)試文件的寫入鎖,這里首先創(chuàng)建了一個(gè)hello文件,之后對(duì)其上寫入鎖,最后釋放寫入鎖:
/*fcntl_write.c測(cè)試文件寫入鎖主函數(shù)部分*/#include<unistd.h>#include<sys/file.h>#include<sys/types.h>#include<sys/stat.h>#include<stdio.h>#include<stdlib.h>intmain(void){intfd;/*首先打開文件*/fd=open("hello",O_RDWR|O_CREAT,0666);if(fd<0){perror("open");exit(1);}/*給文件上寫入鎖*/lock_set(fd,F_WRLCK);getchar();/*給文件解鎖*/lock_set(fd,F_UNLCK);getchar();close(fd);exit(0);}注:先寫主函數(shù),再寫子函數(shù)lock_set。為了能夠使用多個(gè)終端,更好地顯示寫入鎖的作用,本實(shí)例主要在PC機(jī)上測(cè)試,讀者可將其交叉編譯,下載到目標(biāo)板上運(yùn)行。下面是在PC機(jī)上的運(yùn)行結(jié)果。為了使程序有較大的靈活性,筆者采用文件上鎖后由用戶鍵入一任意鍵使程序繼續(xù)運(yùn)行。建議讀者開啟兩個(gè)終端,并且在兩個(gè)終端上同時(shí)運(yùn)行該程序,以達(dá)到多個(gè)進(jìn)程操作一個(gè)文件的效果。在這里,筆者首先運(yùn)行終端一,請(qǐng)讀者注意終端二中的第一句。3、不帶緩存的文件I/O操作(4)Select<1>select函數(shù)說明---處理I/O復(fù)用。I/O處理的模型有5種:阻塞I/O模型、非阻塞模型、I/O多路轉(zhuǎn)接模型、信號(hào)驅(qū)動(dòng)I/O模型、異步I/O模型。阻塞I/O模型:在這種模型下,若所調(diào)用的I/O函數(shù)沒有完成相關(guān)的功能就會(huì)使進(jìn)程掛起,直到相關(guān)數(shù)據(jù)到才會(huì)出錯(cuò)返回。如常見對(duì)管道設(shè)備、終端設(shè)備和網(wǎng)絡(luò)設(shè)備進(jìn)行讀寫時(shí)經(jīng)常會(huì)出現(xiàn)這種情況。非阻塞模型:在這種模型下,當(dāng)請(qǐng)求的I/O操作不能完成時(shí),則不讓進(jìn)程睡眠,而且返回一個(gè)錯(cuò)誤。非阻塞I/O使用戶可以調(diào)用不會(huì)永遠(yuǎn)阻塞的I/O操作,如open、write和read。如果該操作不能完成,則會(huì)立即出錯(cuò)返回,且表示該I/O如果該操作繼續(xù)執(zhí)行就會(huì)阻塞。I/O多路轉(zhuǎn)接模型:在這種模型下,如果請(qǐng)求的I/O操作阻塞,且它不是真正阻塞I/O,而是讓其中的一個(gè)函數(shù)等待,在這期間,I/O還能進(jìn)行其他操作。如本節(jié)要介紹的select函數(shù)和poll函數(shù),就是屬于這種模型。信號(hào)驅(qū)動(dòng)I/O模型:在這種模型下,通過安裝一個(gè)信號(hào)處理程序,系統(tǒng)可以自動(dòng)捕獲特定信號(hào)的到來,從而啟動(dòng)I/O。這是由內(nèi)核通知用戶何時(shí)可以啟動(dòng)一個(gè)I/O操作決定的。異步I/O模型:在這種模型下,當(dāng)一個(gè)描述符已準(zhǔn)備好,可以啟動(dòng)I/O時(shí),進(jìn)程會(huì)通知內(nèi)核?,F(xiàn)在,并不是所有的系統(tǒng)都支持這種模型。select的I/O多路轉(zhuǎn)接模型是處理I/O復(fù)用的一個(gè)高效的方法,它可以具體設(shè)置每一個(gè)所關(guān)心的文件描述符的條件、希望等待的時(shí)間等,從select函數(shù)返回時(shí),內(nèi)核會(huì)通知用戶已準(zhǔn)備好的文件描述符的數(shù)量、已準(zhǔn)備好的條件等。通過使用select返回值,就可以調(diào)用相應(yīng)的I/O處理函數(shù)了。<2>select函數(shù)格式
(表3.19)<3>使用實(shí)例本例主要表現(xiàn)了如何使用select函數(shù),而其中的I/O操作是不會(huì)阻塞的。本實(shí)例中主要實(shí)現(xiàn)將文件hello1里的內(nèi)容讀出,并將此內(nèi)容每隔10s寫入hello2中去。在這里建立了兩個(gè)描述符集,其中一個(gè)描述符集inset1是用于讀取文件內(nèi)容,另一個(gè)描述符集inset2是用于寫入文件的。兩個(gè)文件描述符fds[0]和fds[1]分別指向這一文件描述符。在首先初始化完各文件描述符集之后,就開始了循環(huán)測(cè)試這兩個(gè)文件描述符是否可讀寫,由于在這里沒有阻塞,所以文件描述符處于準(zhǔn)備就緒的狀態(tài)。這時(shí),就分別對(duì)文件描述符fds[0]和fsd[1]進(jìn)行讀寫操作。/*select.c*/#include<fcntl.h>#include<stdio.h>#include<unistd.h>#include<stdlib.h>#include<time.h>intmain(void){intfds[2];charbuf[7];inti,rc,maxfd;fd_setinset1,inset2;structtimevaltv;/*首先按一定的權(quán)限打開hello1文件*/if((fds[0]=open("hello1",O_RDWR|O_CREAT,0666))<0)perror("openhello1");/*再按一定的權(quán)限打開hello2文件*/if((fds[1]=open("hello2",O_RDWR|O_CREAT,0666))<0)perror("openhello2");if((rc=write(fds[0],"Hello!\n",7)))printf("rc=%d\n",rc);lseek(fds[0],0,SEEK_SET);/*取出兩個(gè)文件描述符中的較大者*/maxfd=fds[0]>fds[1]?fds[0]:fds[1];/*初始化讀集合inset1,并在讀集合中加入相應(yīng)的描述集*/FD_ZERO(&inset1);FD_SET(fds[0],&inset1);/*初始化寫集合inset2,并在寫集合中加入相應(yīng)的描述集*/FD_ZERO(&inset2);FD_SET(fds[1],&inset2);tv.tv_sec=2;tv.tv_usec=0;/*循環(huán)測(cè)試該文件描述符是否準(zhǔn)備就緒,并調(diào)用select函數(shù)對(duì)相關(guān)文件描述符做對(duì)應(yīng)操作*/while(FD_ISSET(fds[0],&inset1)||FD_ISSET(fds[1],&inset2)){if(select(maxfd+1,&inset1,&inset2,NULL,&tv)<0)perror("select");else{if(FD_ISSET(fds[0],&inset1)){rc=read(fds[0],buf,7);if(rc>0){buf[rc]='\0';printf("read:%s\n",buf);}elseperror("read");}if(FD_ISSET(fds[1],&inset2)){rc=write(fds[1],buf,7);if(rc>0)
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 部審人教版七年級(jí)數(shù)學(xué)下冊(cè)聽評(píng)課記錄《5.2.1 平行線》2
- 人教版地理七年級(jí)上冊(cè)第二節(jié)《地球的運(yùn)動(dòng)》聽課評(píng)課記錄3
- 湘教版數(shù)學(xué)八年級(jí)上冊(cè)4.1《不等式》聽評(píng)課記錄
- 人教版地理八年級(jí)下冊(cè)7.2《魚米之鄉(xiāng)-長江三角洲地區(qū)》聽課評(píng)課記錄2
- 用戶體驗(yàn)設(shè)計(jì)服務(wù)協(xié)議書(2篇)
- 環(huán)境整治用功協(xié)議書(2篇)
- 人教部編版八年級(jí)道德與法治上冊(cè):8.1《國家好 大家才會(huì)好-國家利益的含義》聽課評(píng)課記錄
- 【人教版】河南省八年級(jí)地理上冊(cè)3.2土地資源聽課評(píng)課記錄1新版新人教版
- 新版華東師大版八年級(jí)數(shù)學(xué)下冊(cè)《17.3.2一次函數(shù)的圖象2》聽評(píng)課記錄22
- 北京課改版歷史八年級(jí)上冊(cè)第3課《第二次鴉片戰(zhàn)爭(zhēng)》聽課評(píng)課記錄
- 設(shè)備維保的維修流程與指導(dǎo)手冊(cè)
- 急性腎小球腎炎病人護(hù)理課件
- 招標(biāo)代理服務(wù)的關(guān)鍵流程與難點(diǎn)解析
- GB/T 5465.2-2023電氣設(shè)備用圖形符號(hào)第2部分:圖形符號(hào)
- 材料預(yù)定協(xié)議
- 2023年河北省中考數(shù)學(xué)試卷(含解析)
- 《學(xué)習(xí)的本質(zhì)》讀書會(huì)活動(dòng)
- 高氨血癥護(hù)理課件
- 物流營銷(第四版) 課件 胡延華 第3、4章 物流目標(biāo)客戶選擇、物流服務(wù)項(xiàng)目開發(fā)
- 《石油化工電氣自動(dòng)化系統(tǒng)設(shè)計(jì)規(guī)范》
- Q-GGW-BF-0117-2023天然氣管道無人站技術(shù)規(guī)范
評(píng)論
0/150
提交評(píng)論