Linux 環(huán)境下的C語(yǔ)言編程_第1頁(yè)
Linux 環(huán)境下的C語(yǔ)言編程_第2頁(yè)
Linux 環(huán)境下的C語(yǔ)言編程_第3頁(yè)
Linux 環(huán)境下的C語(yǔ)言編程_第4頁(yè)
Linux 環(huán)境下的C語(yǔ)言編程_第5頁(yè)
已閱讀5頁(yè),還剩98頁(yè)未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡(jiǎn)介

Linux環(huán)境下的

C語(yǔ)言編程第一部分:Linux下的C編程實(shí)戰(zhàn)之開發(fā)平臺(tái)搭建準(zhǔn)備工作建議在PC內(nèi)存足夠大的情況下,不要直接安裝Linux操作系統(tǒng),最好把它安裝在運(yùn)行VMWare虛擬機(jī)軟件的Windows平臺(tái)上,如下圖:1.Vim和Emacs編輯器在Linux平臺(tái)下,可用任意一個(gè)文本編輯工具編輯源代碼。Vim(viimprove)是Linux下功能強(qiáng)大的編輯器,是由UNIX系統(tǒng)下的傳統(tǒng)文本編輯器vi發(fā)展而來(lái),是vi的一個(gè)增強(qiáng)版本,有彩色和高亮等特性,對(duì)編程有很大幫助。主菜單-編程-viImproved命令來(lái)運(yùn)行x-windows下的vim。Emacs即EditorMACroS(編輯器宏)的縮寫,是一種強(qiáng)大的文本編輯器,在程序員和其他以技術(shù)工作為主的計(jì)算機(jī)用戶中廣受歡迎。使用vim編輯helloworld程序使用emacs編輯helloworld程序2.GCC編譯器GCC是Linux平臺(tái)下最重要的開發(fā)工具,它是GNU的C和C++編譯器,其基本用法為:gcc[options][filenames]

該命令按編譯選項(xiàng)(參數(shù)options)指定的操作對(duì)給定的文件進(jìn)行編譯處理。編譯一輸出“HelloWorld”的程序:

main()

{

printf("HelloWorld\n");

}2.GCC編譯器最簡(jiǎn)單的編譯方法是不指定任何編譯選項(xiàng),它會(huì)為目標(biāo)程序生成默認(rèn)的文件名a.outgcc

helloworld.co選項(xiàng):編譯來(lái)為將產(chǎn)生的可執(zhí)行文件指定一個(gè)文件名。例如,將上述名為helloworld.c的C程序編譯為名叫helloworld的可執(zhí)行文件,輸入如下命令:gcc-ohelloworld

helloworld.c

2.GCC編譯器-常用選項(xiàng)c選項(xiàng):告訴GCC僅把源代碼(.c文件)編譯為目標(biāo)代碼(.o文件)而跳過(guò)匯編和連接的步驟;它能使編譯多個(gè)C程序時(shí)的速度更快且容易管理。例如用戶將已編輯好的test.c文件編譯成名為test.o的目標(biāo)文件。可以使用命令gcc-ctest.cs選項(xiàng):告訴GCC在為C代碼產(chǎn)生了匯編語(yǔ)言文件后停止編譯。GCC產(chǎn)生的匯編語(yǔ)言文件的缺省擴(kuò)展名是.s。將生成helloworld.c的匯編代碼,使用的是AT&T匯編。用emacs打開匯編代碼如下圖。用emacs打開的Hello.c的匯編代碼2.GCC編譯器-常用選項(xiàng)E選項(xiàng):指示編譯器僅對(duì)輸入文件進(jìn)行預(yù)處理,但不匯編和連接O(-O1)選項(xiàng):告訴GCC對(duì)源代碼進(jìn)行基本優(yōu)化從而使得程序執(zhí)行地更快;而-O2選項(xiàng)告訴GCC產(chǎn)生盡可能小和盡可能快的代碼。使用-O2選項(xiàng)編譯的速度比使用-O時(shí)慢,但產(chǎn)生的代碼執(zhí)行速度會(huì)更快。Wall選項(xiàng):顯示附加的警告信息。例如在上述程序中去掉return0;語(yǔ)句,之后重新編譯gcc–Wall–ohellohello.c將得到的警告信息:hello.c:5:warning:controlreachesendofnon-voidfunction3.GDB調(diào)試器GCC用于編譯程序,而Linux的另一個(gè)GNU工具gdb則用于調(diào)試程序。gdb是一個(gè)用來(lái)調(diào)試C和C++程序的強(qiáng)力調(diào)試器,通過(guò)它進(jìn)行一系列調(diào)試工作。gdb主要提供一下功能:監(jiān)視程序中變量的值得變化設(shè)置斷點(diǎn),使程序在指定的代碼上暫停執(zhí)行,便于觀察單步執(zhí)行代碼分析崩潰程序產(chǎn)生的core文件3.GDB調(diào)試器★gdb最常用的命令如下file:裝入想要調(diào)試的可執(zhí)行文件。kill:終止正在調(diào)試的程序。list:列表顯示源代碼。next:執(zhí)行一行源代碼但不進(jìn)入函數(shù)內(nèi)部。step:執(zhí)行一行源代碼而且進(jìn)入函數(shù)內(nèi)部。run:執(zhí)行當(dāng)前被調(diào)試的程序quit:終止gdbwatch:監(jiān)視一個(gè)變量的值break:在代碼里設(shè)置斷點(diǎn),程序執(zhí)行到這里時(shí)掛起3.GDB調(diào)試器舉例說(shuō)明怎樣用GDB調(diào)試一個(gè)求0+1+2+3+…+99的程序:

/*Filename:sum.c*/

main()

{

inti,sum;

sum=0;

for(i=0;i<100;i++)

{

sum+=i;

}

printf("thesumof1+2+...+is%d",sum);

}3.GDB調(diào)試器3.GDB調(diào)試器執(zhí)行如下命令編譯sum.c(加-g選項(xiàng)產(chǎn)生debug信息):

gcc–g–osumsum.c在命令行上鍵入gdbsum并按回車鍵就可以開始調(diào)試sum了,再運(yùn)行run命令執(zhí)行sum,屏幕上將看到如下內(nèi)容:3.GDB調(diào)試器list命令:list命令用于列出源代碼,對(duì)上述程序運(yùn)行l(wèi)ist,將出現(xiàn)如下畫面(源代碼被標(biāo)行號(hào)):

3.GDB調(diào)試器根據(jù)列出的源程序,如果將斷點(diǎn)設(shè)置在第4行,只需在gdb

命令行提示符下鍵入如下命令設(shè)置斷點(diǎn):(gdb)break4Breakpoint1at0x8048338:filesum.cline4這時(shí)再run,程序會(huì)停止在第4行:Startingprogram:/root/sumBreakpoint1,main()atsum.cline44sum=03.GDB調(diào)試器設(shè)置斷點(diǎn)的另一種語(yǔ)法是break<function>,它在進(jìn)入指定函數(shù)(function)時(shí)停住。相反的,clear用于清除所有的已定義的斷點(diǎn)clear<function>清除設(shè)置在函數(shù)上的斷點(diǎn);clear<linenum>則清除設(shè)置在指定行上的斷點(diǎn)。3.GDB調(diào)試器watch命令:用于觀查變量或表達(dá)式的值watch命令觀查sum變量只需要運(yùn)行:watchsumwatch命令觀查表達(dá)式:watch<expr>

為表達(dá)式(變量)expr設(shè)置一個(gè)觀察點(diǎn),變量表達(dá)式值有變化時(shí),程序會(huì)停止執(zhí)行。要觀查當(dāng)前設(shè)置的watch,可以使用infowatchpoints命令。3.GDB調(diào)試器next、step命令:next、step用于單步執(zhí)行,在執(zhí)行的過(guò)程中,被watch變量的變化情況將實(shí)時(shí)呈現(xiàn)(分別顯示Oldvalue和Newvalue),如下圖:next、step命令的區(qū)別在于step遇到函數(shù)調(diào)用,會(huì)跳轉(zhuǎn)到該函數(shù)定義的開始行去執(zhí)行,而next則不進(jìn)入到函數(shù)內(nèi)部,它把函數(shù)調(diào)用語(yǔ)句當(dāng)作一條普通語(yǔ)句執(zhí)行。4.Make編譯和連接的區(qū)別編譯器使用源碼文件來(lái)產(chǎn)生某種形式的目標(biāo)文件,在編譯過(guò)程中,外部的符號(hào)參考并沒(méi)有被解釋或替換(即外部全局變量和函數(shù)并沒(méi)有被找到)。因此,在編譯階段所報(bào)的錯(cuò)誤一般都是語(yǔ)法錯(cuò)誤。連接器則用于連接目標(biāo)文件和程序包,生成一個(gè)可執(zhí)行程序。在連接階段,一個(gè)目標(biāo)文件中對(duì)別的文件中的符號(hào)的參考被解釋,如果有符號(hào)不能找到,會(huì)報(bào)告連接錯(cuò)誤。4.Make編譯和連接的一般步驟是:第一階段把源文件一個(gè)一個(gè)的編譯成目標(biāo)文件,第二階段把所有的目標(biāo)文件加上需要的程序包連接成一個(gè)可執(zhí)行文件。這樣的過(guò)程需要使用大量的gcc命令。而make則使從大量源文件的編譯和連接工作中解放出來(lái),綜合為一步完成。4.MakeGNUMake的主要工作是讀進(jìn)一個(gè)文本文件,稱為makefile。makefile文件記錄了哪些文件(目的文件,目的文件不一定是最后的可執(zhí)行程序,它可以是任何一種文件)由哪些文件(依靠文件)產(chǎn)生,用什么命令來(lái)產(chǎn)生。Make依靠此makefile中的信息檢查磁盤上的文件,如果目的文件的創(chuàng)建或修改時(shí)間比它的一個(gè)依靠文件舊的話,make就執(zhí)行相應(yīng)的命令,以便更新目的文件。

4.Makemakefile文件的編寫makefile文件是一個(gè)文本文件,用于描述整個(gè)項(xiàng)目和各個(gè)文件之間的依賴關(guān)系。它由多個(gè)規(guī)則組成。makefile文件的規(guī)則遵循以下結(jié)構(gòu)#remark注釋行target:file1file2[…]二進(jìn)制文件或者目標(biāo)文件command1命令command2[…]4.Make例如:下面三個(gè)文件,add.h用于聲明add函數(shù),add.c提供兩個(gè)整數(shù)相加的函數(shù)體,而main.c中調(diào)用add函數(shù):

/*filename:add.h*/

externint

add(inti,intj);

/*filename:add.c*/

int

add(inti,intj)

{

returni+j;

}

/*filename:main.c*/

#include"add.h"

main()

{

inta,b;

a=2;

b=3;

printf("thesumofa+bis%d",add(a+b));}怎樣為上述三個(gè)文件產(chǎn)生makefile呢?4.Make為上述三個(gè)文件產(chǎn)生makefile的方法如下:

test:main.o

add.o

gcc

main.o

add.o-otest

main.o:main.c

add.h

gcc-cmain.c-omain.o

add.o:add.c

add.h

gcc-cadd.c-oadd.o

4.Make上述makefile文件的含義利用add.c和add.h文件執(zhí)行g(shù)cc-cadd.c-oadd.o命令產(chǎn)生add.o目標(biāo)代碼。利用main.c和add.h文件執(zhí)行g(shù)cc-cmain.c-omain.o命令產(chǎn)生main.o目標(biāo)代碼。最后利用main.o和add.o文件(兩個(gè)模塊的目標(biāo)代碼)執(zhí)行g(shù)cc

main.o

add.o-otest命令產(chǎn)生可執(zhí)行文件test。可以使用gcc-MMmain.c自動(dòng)尋找源文件中的頭文件,并形成依賴關(guān)系。輸出為:main.o

main.c

add.h4.Make可在makefile中加入變量。另外,環(huán)境變量在make過(guò)程中也被解釋成make的變量。這些變量是大小寫敏感的,一般使用大寫字母。要定義一個(gè)變量,只需要在一行的開始寫下這個(gè)變量的名字,后面跟一個(gè)=號(hào),再跟變量的值。引用變量的方法是寫一個(gè)$符號(hào),后面跟(變量名)。4.Make把前面的makefile

利用變量重寫一遍(并假設(shè)使用-Wall-O–g編譯選項(xiàng)):OBJS=main.o

add.oCC=gccCFLAGS=-Wall-O-gtest:$(OBJS)$(CC)$(OBJS)-otestmain.o:main.c

add.h$(CC)$(CFLAGS)-cmain.c-omain.oadd.o:add.c

add.h$(CC)$(CFLAGS)-cadd.c-oadd.o

4.Makemakefile

中還可定義清除(clean)目標(biāo),可用來(lái)清除編譯過(guò)程中產(chǎn)生的中間文件,例如在上述makefile文件中添加下列代碼:clean:

rm-f*.o運(yùn)行makeclean時(shí),將執(zhí)行rm-f*.o命令,刪除所有編譯過(guò)程中產(chǎn)生的中間文件。

4.MakeMake的運(yùn)行GUNmake默認(rèn)在當(dāng)前的目錄下一次查找GUNmake文件,Makefile文件和makefile文件,找到后讀取文件執(zhí)行。給make命令指定一個(gè)特殊名字的makefile文件make–fhchen.mk4.Make自己動(dòng)手編寫makefile仍然是很復(fù)雜和煩瑣的,而且很容易出錯(cuò)。因此,GNU也提供了Automake和Autoconf來(lái)輔助快速自動(dòng)產(chǎn)生makefile。

4.Make使用autoconf和automake來(lái)進(jìn)行自動(dòng)化配置和生成Makefile的流程可以概括如下:運(yùn)行autoscan命令。將configure.scan文件重命名為configure.in,并修改configure.in文件。運(yùn)行aclocal命令得到aclocal.m4文件。運(yùn)行autoconf命令得到configure文件。在工程目錄下新建Makefile.am文件,如果存在子目錄,子目錄中也要?jiǎng)?chuàng)建此文件。將/usr/share/automake-1.X/目錄下的depcomp和compile文件復(fù)制到需要處理目錄下。運(yùn)行automake-a命令得到Makefile.in文件。運(yùn)行./configure腳本4.Make從例子程序helloworld開始。過(guò)程如下:新建三個(gè)文件:

helloworld.c

configure.in

Makefile.am然后執(zhí)行

aclocal;autoconf;automake--add-missing;./configure;make;./helloworld

Makefile被產(chǎn)生出來(lái),而且可以將helloworld.c編譯通過(guò)。小結(jié)本部分主要闡述了Linux程序的編寫、編譯、調(diào)試方法及make,實(shí)際上是引導(dǎo)學(xué)習(xí)怎樣在Linux下編程,為后續(xù)章節(jié)做好準(zhǔn)備。

第二部分

Linux下的C編程實(shí)戰(zhàn)之文件系統(tǒng)編程

Linux平臺(tái)下文件編程在Linux平臺(tái)下對(duì)文件編程可以使用兩類函數(shù):Linux操作系統(tǒng)文件API;C語(yǔ)言I/O庫(kù)函數(shù)。前者依賴于Linux系統(tǒng)調(diào)用,后者實(shí)際上與操作系統(tǒng)是獨(dú)立的,因?yàn)樵谌魏尾僮飨到y(tǒng)下,使用C語(yǔ)言I/O庫(kù)函數(shù)操作文件的方法都是相同的。1.Linux文件API-創(chuàng)建創(chuàng)建int

create(constchar*filename,mode_tmode);

參數(shù)mode指定新建文件的存取權(quán)限,它同umask一起決定文件的最終權(quán)限(mode&umask).umask代表了文件在創(chuàng)建時(shí)需要去掉的一些存取權(quán)限。umask可通過(guò)系統(tǒng)調(diào)用umask()來(lái)改變:

int

umask(int

newmask);

該調(diào)用將umask設(shè)置為newmask,然后返回舊的umask,它只影響讀、寫和執(zhí)行權(quán)限。1.Linux文件API-創(chuàng)建mode可以是以下情況的組合,可以通過(guò)上述宏進(jìn)行“或”邏輯產(chǎn)生標(biāo)志。

標(biāo)志含義S_IRUSR

用戶可以讀

S_IWUSR

用戶可以寫

S_IXUSR

用戶可以執(zhí)行

S_IRWXU

用戶可以讀、寫、執(zhí)行

S_IRGRP

組可以讀

S_IWGRP組可以寫S_IXGRP組可以執(zhí)行S_IRWXG組可以讀寫執(zhí)行1.Linux文件API-創(chuàng)建mode可以是以下情況的組合,可以通過(guò)上述宏進(jìn)行“或”邏輯產(chǎn)生標(biāo)志。標(biāo)志含義S_IROTH其他人可以讀S_IWOTH其他人可以寫S_IXOTH其他人可以執(zhí)行S_IRWXO其他人可以讀、寫、執(zhí)行S_ISUID設(shè)置用戶執(zhí)行IDS_ISGID設(shè)置組的執(zhí)行ID1.Linux文件API-創(chuàng)建用數(shù)字來(lái)表示:Linux總共用5個(gè)數(shù)字來(lái)表示文件的各種權(quán)限:第一位表示設(shè)置用戶ID;第二位表示設(shè)置組ID;第三位表示用戶自己的權(quán)限位;第四位表示組的權(quán)限;最后一位表示其他人的權(quán)限。每個(gè)數(shù)字可以取1(執(zhí)行權(quán)限)、2(寫權(quán)限)、4(讀權(quán)限)、0(無(wú))或者是這些值的和。1.Linux文件API-創(chuàng)建★用數(shù)字來(lái)表示:例如,要?jiǎng)?chuàng)建一個(gè)用戶可讀、可寫、可執(zhí)行,但是組沒(méi)有權(quán)限,其他人可以讀、可以執(zhí)行的文件,并設(shè)置用戶ID位。應(yīng)該使用的模式是1(設(shè)置用戶ID)、0(不設(shè)置組ID)、7(1+2+4,讀、寫、執(zhí)行)、0(沒(méi)有權(quán)限)、5(1+4,讀、執(zhí)行)即10705

1.Linux文件API-打開打開int

open(constchar*pathname,intflags);int

open(constchar*pathname,intflags,mode_tmode);如果文件打開成功,open函數(shù)會(huì)返回一個(gè)文件描述符,以后對(duì)該文件的所有操作就可以通過(guò)對(duì)這個(gè)文件描述符進(jìn)行操作來(lái)實(shí)現(xiàn)。open函數(shù)有兩個(gè)形式,其中pathname是要打開的文件名(包含路徑名稱,缺省是認(rèn)為在當(dāng)前路徑下面)。

1.Linux文件API-打開打開flags可以是下面的一個(gè)值或者是幾個(gè)值的組合,O_RDONLY、O_WRONLY、O_RDWR三個(gè)標(biāo)志只能使用任意的一個(gè)。1.Linux文件API-打開打開如果使用了O_CREATE標(biāo)志,則使用的函數(shù)是int

open(constchar*pathname,int

flags,mode_tmode);這時(shí)要指定mode標(biāo)志,用來(lái)表示文件的訪問(wèn)權(quán)限。以O(shè)_CREAT為標(biāo)志的open實(shí)際上實(shí)現(xiàn)了文件創(chuàng)建的功能。例如:

open("test",O_CREAT,10705);

open("test",O_CREAT,S_IRWXU|S_IROTH|S_IXOTH|S_ISUID);

1.Linux文件API-讀寫讀寫Linux中提供文件讀寫的系統(tǒng)調(diào)用是read、write函數(shù):

int

read(int

fd,constvoid*buf,size_tlength);

int

write(int

fd,constvoid*buf,size_tlength);參數(shù)buf為指向緩沖區(qū)的指針,length為緩沖區(qū)的大小(以字節(jié)為單位)。1.Linux文件API-讀寫int

read(int

fd,constvoid*buf,size_tlength);函數(shù)read實(shí)現(xiàn)從文件描述符fd所指定的文件中讀取length個(gè)字節(jié)到buf所指向的緩沖區(qū)中,返回值為實(shí)際讀取的字節(jié)數(shù)。int

write(int

fd,constvoid*buf,size_tlength);函數(shù)write實(shí)現(xiàn)將把length個(gè)字節(jié)從buf指向的緩沖區(qū)中寫到文件描述符fd所指向的文件中,返回值為實(shí)際寫入的字節(jié)數(shù)。1.Linux文件API-定位定位:對(duì)于隨機(jī)文件,我們可以隨機(jī)的指定位置讀寫,使用如下函數(shù)進(jìn)行定位:

int

lseek(int

fd,offset_toffset,intwhence);lseek()將文件讀寫指針相對(duì)whence移動(dòng)offset個(gè)字節(jié)。操作成功時(shí),返回文件指針相對(duì)于文件頭的位置。參數(shù)whence可使用下述值:SEEK_SET:相對(duì)文件開頭SEEK_CUR:相對(duì)文件讀寫指針的當(dāng)前位置SEEK_END:相對(duì)文件末尾1.Linux文件API-定位定位:offset可取負(fù)值,例如下述調(diào)用可將文件指針相對(duì)當(dāng)前位置向前移動(dòng)5個(gè)字節(jié):

lseek(fd,-5,SEEK_CUR);由于lseek函數(shù)的返回值為文件指針相對(duì)于文件頭的位置,因此下列調(diào)用的返回值就是文件的長(zhǎng)度:

lseek(fd,0,SEEK_END);1.Linux文件API-關(guān)閉關(guān)閉當(dāng)操作完成以后,要關(guān)閉文件,只要調(diào)用close即可,其中fd是要關(guān)閉的文件描述符:

int

close(int

fd);1.Linux文件API-編程實(shí)例例程:編寫一個(gè)程序,在當(dāng)前目錄下創(chuàng)建用戶可讀寫文件“hello.txt”,在其中寫入“Hello,softwareweekly”,關(guān)閉該文件。再次打開該文件,讀取其中的內(nèi)容并輸出在屏幕上。

#include<sys/types.h>//類型#include<sys/stat.h>//獲取文件屬性#include<fcntl.h>//文件描述詞操作#include<stdio.h>

#defineLENGTH100

main()

{

int

fd,len;

charstr[LENGTH];

fd=open(“hello.txt”,O_CREAT|O_RDWR,S_IRUSR|S_IWUSR);/*創(chuàng)建并打開文件,以讀寫的方式打開,用戶可以讀、用戶可以寫*/

1.Linux文件API-編程實(shí)例if(fd)

{

write(fd,"Hello,SoftwareWeekly",strlen("Hello,softwareweekly"));/*寫入Hello,softwareweekly字符串*/

close(fd);

}

fd=open(“hello.txt”,O_RDWR);//以讀寫方式打開

len=read(fd,str,LENGTH);/*讀取文件內(nèi)容*/

str[len]='\0';

printf("%s\n",str);

close(fd);

}1.Linux文件API-編程實(shí)例1.Linux文件API-編程實(shí)例編譯并運(yùn)行,執(zhí)行結(jié)果如下[root@dl

root]#gcc–g–ohello./hello.c[root@dlroot]#./helloHello,softwareweekly

3.C語(yǔ)言庫(kù)函數(shù)C庫(kù)函數(shù)的文件操作實(shí)際上是獨(dú)立于具體的操作系統(tǒng)平臺(tái)的,不管是在DOS、Windows、Linux還是在VxWorks中都是這些函數(shù).

3.C語(yǔ)言庫(kù)函數(shù)-創(chuàng)建和打開創(chuàng)建和打開FILE*fopen(constchar*path,constchar*mode);fopen()實(shí)現(xiàn)打開指定文件,參數(shù)path字符串包含欲打開的文件路徑及文件名

,mode為打開模式.返回值:文件指針名。必須被說(shuō)明為FILE類型的指針變量。3.C語(yǔ)言庫(kù)函數(shù)-創(chuàng)建和打開C語(yǔ)言中支持的打開模式如下表,其中b用于區(qū)分二進(jìn)制文件和文本文件,在DOS、Windows系統(tǒng)中是有區(qū)分的,但Linux不區(qū)分二進(jìn)制文件和文本文件。

標(biāo)志含義r,rb以只讀方式打開w,wb以只寫方式打開。如果文件不存在,則創(chuàng)建該文件,否則文件被截?cái)郺,ab以追加方式打開。如果文件不存在,則創(chuàng)建該文件r+,r+b,rb+以讀寫方式打開+,w+b,wh+以讀寫方式打開。如果文件不存在時(shí),創(chuàng)建新文件,否則文件被截?cái)郺+,a+b,ab+以讀和追加方式打開。如果文件不存在,創(chuàng)建新文件3.C語(yǔ)言庫(kù)函數(shù)-讀寫讀寫:C庫(kù)函數(shù)支持以字符、字符串等為單位,支持按照某中格式進(jìn)行文件的讀寫,這一組函數(shù)為:int

fgetc(FILE*stream);從流中讀一個(gè)字符int

fputc(intc,FILE*stream);送一個(gè)字符到流中char*fgets(char*s,intn,FILE*stream);從流中讀取一字符串

int

fputs(constchar*s,FILE*stream);送一個(gè)字符串到流中3.C語(yǔ)言庫(kù)函數(shù)-讀寫int

fprintf(FILE*stream,constchar*format,...);傳送格式化輸出到一個(gè)文件中,成功時(shí)返回轉(zhuǎn)換的字節(jié)數(shù),失敗時(shí)返回一個(gè)負(fù)數(shù)。

fprintf(stream,"%s%c",s,c);

fprintf(stream,"%d\n",i);int

fscanf(FILE*stream,constchar*format,...);從一個(gè)流中執(zhí)行格式化輸入

if(fscanf(stdin,"%d",&i))

printf("Theintegerreadwas:%d\n",i);

3.C語(yǔ)言庫(kù)函數(shù)-讀寫讀寫:size_t

fread(void*ptr,size_tsize,size_tn,FILE*stream);size_t

fwrite(constvoid*ptr,size_tsize,size_tn,FILE*stream);fread()實(shí)現(xiàn)從流stream中讀取n個(gè)字段,每個(gè)字段為size字節(jié),并將讀取的字段放入ptr所指的字符數(shù)組中,返回實(shí)際已讀取的字段數(shù)。write()實(shí)現(xiàn)從緩沖區(qū)ptr所指的數(shù)組中把n個(gè)字段寫到流stream中,每個(gè)字段長(zhǎng)為size個(gè)字節(jié),返回實(shí)際寫入的字段數(shù)。3.C語(yǔ)言庫(kù)函數(shù)-定位定位:C庫(kù)函數(shù)還提供了讀寫過(guò)程中的定位能力,這些函數(shù)包括:int

fgetpos(FILE*stream,fpos_t*pos);//將文件流的文件位置指示符存儲(chǔ)在pos變量中int

fsetpos(FILE*stream,constfpos_t*pos);//將文件指針定位在pos指定的位置上返回值:成功返回0,否則返回非0。#include<stdio.h>voidmain(void){FILE*fp;

fpos_tpos;charbuffer[50];if((fp=fopen("test.txt","rb"))==NULL)/*以只讀方式打開名為test.txt的文件*/

printf("Troubleopeningfile\n");else{pos=10;/*設(shè)置pos值*/if(fsetpos(fp,&pos)!=0)/*應(yīng)用fsetpos函數(shù)將文件指針fp按照pos指定的位置在文件中定位*/

perror("fsetposerror");else{

/*從新定位的文件指針開始讀取16個(gè)字符到buffer緩沖區(qū)*/fread(buffer,sizeof(char),16,fp);printf("16bytesatbyte%ld:%.16s\n",pos,buffer);/*顯示結(jié)果*/}}

fclose(fp);}

3.C語(yǔ)言庫(kù)函數(shù)-定位首先,程序以只讀方式打開名為test.txt的文件。在這里,test.txt文件中已存入字符串Thisisatestfortestingthefunctionoffsetpos.將pos設(shè)置為10。應(yīng)用fsetpos函數(shù)將文件指針fp按照pos指定的位置在文件中定位。這樣文件指針fp指向字符串中test的字母t。再?gòu)男露ㄎ坏奈募羔橀_始讀取16個(gè)字符到buffer緩沖區(qū),也就是說(shuō)讀取字符串"testfortesting"到緩沖區(qū)buffer。最后顯示結(jié)果:16bytesatbyte10:testfortesting

3.C語(yǔ)言庫(kù)函數(shù)-定位int

fseek(FILE*stream,longoffset,intwhence);stream為文件指針offset為偏移量,整數(shù)表示正向偏移,負(fù)數(shù)為負(fù)向偏移whence設(shè)定從文件的哪里開始偏移,可能取值為:SEEK_SET:文件開頭0SEEK_CUR:當(dāng)前位置1SEEK_END:文件結(jié)尾2fseek(fp,100L,0);把fp指針移動(dòng)到離文件開頭100字節(jié)處;fseek(fp,100L,1);把fp指針移動(dòng)到離文件當(dāng)前位置100字節(jié)處;fseek(fp,100L,2);把fp指針退回到離文件結(jié)尾100字節(jié)處。3.C語(yǔ)言庫(kù)函數(shù)-關(guān)閉關(guān)閉:利用C庫(kù)函數(shù)關(guān)閉文件的操作:

int

fclose(FILE*stream);3.C語(yǔ)言庫(kù)函數(shù)-編程實(shí)例例程:編寫一個(gè)程序,在當(dāng)前目錄下創(chuàng)建用戶可讀寫文件“hello.txt”,在其中寫入“Hello,softwareweekly”,關(guān)閉該文件。再次打開該文件,讀取其中的內(nèi)容并輸出在屏幕上。

#include<stdio.h>

#defineLENGTH100

main()

{

FILE*fd;

charstr[LENGTH];

fd=fopen("hello.txt","w+");/*創(chuàng)建并打開文件*/

if(fd)

{

fputs("Hello,SoftwareWeekly",fd);/*寫入Hello,softwareweekly字符串*/

fclose(fd);

}

fd=fopen("hello.txt","r");

fgets(str,LENGTH,fd);/*讀取文件內(nèi)容*/

printf("%s\n",str);

fclose(fd);

}3.小結(jié)Linux提供的虛擬文件系統(tǒng)為多種文件系統(tǒng)提供了統(tǒng)一的接口,Linux的文件編程有兩種途徑:基于Linux系統(tǒng)調(diào)用;基于C庫(kù)函數(shù)這兩種編程所涉及到文件操作有新建、打開、讀寫和關(guān)閉,對(duì)隨機(jī)文件還可以定位。

第二部分

Linux下的C編程實(shí)戰(zhàn)之進(jìn)程控制與進(jìn)程通信編程1.進(jìn)程的基本概念進(jìn)程是具有一定功能的程序,是關(guān)于一個(gè)數(shù)據(jù)集合的一次執(zhí)行過(guò)程。多個(gè)進(jìn)程可以同時(shí)運(yùn)行。Linux進(jìn)程在內(nèi)存中包含三部分?jǐn)?shù)據(jù):代碼段:存放了程序的代碼,代碼段可以為機(jī)器中運(yùn)行同一程序的數(shù)個(gè)進(jìn)程共享。堆棧段:存放的是子程序(函數(shù))的返回地址、子程序的參數(shù)及程序的局部變量。數(shù)據(jù)段:存放程序的全局變量、常數(shù)以及動(dòng)態(tài)數(shù)據(jù)分配的數(shù)據(jù)空間。堆棧段和數(shù)據(jù)段不能為運(yùn)行同一程序的數(shù)個(gè)進(jìn)程共享。2.進(jìn)程控制-進(jìn)程的創(chuàng)建(1)派生進(jìn)程系統(tǒng)調(diào)用fork用于派生一個(gè)進(jìn)程,其說(shuō)明如下:

#include<unistd.h>

pid_t

fork(void);

pid_t

vfork(void);調(diào)用fork時(shí),系統(tǒng)創(chuàng)建一個(gè)與當(dāng)前進(jìn)程(父進(jìn)程)相同的新進(jìn)程(子進(jìn)程)。子進(jìn)程是父進(jìn)程的一個(gè)復(fù)制,子進(jìn)程拷貝父進(jìn)程的數(shù)據(jù)段、代碼段2.進(jìn)程控制-進(jìn)程的創(chuàng)建fork調(diào)用將執(zhí)行兩次返回,它將從父進(jìn)程和子進(jìn)程中分別返回。從父進(jìn)程返回時(shí)的返回值為子進(jìn)程的PID,而從子進(jìn)程返回時(shí)的返回值為0,并且返回都將執(zhí)行fork之后的語(yǔ)句。調(diào)用出錯(cuò)時(shí),返回值為-1#include<sys/types.h>#include<stdio.h>#include<unistd.h>intmain(){

pid_t

pid;

pid=fork();

if((pid)<0){

printf(“forkerror!\n”);exit(1);}elseif(pid=0)

printf(“childprocessisprinting.IDis%d\n”,getpid());else

printf(“parentprocessisprinting.IDis%d\n”,getpid());}拷貝代碼段的實(shí)例運(yùn)行結(jié)果:

[root@lwm

liweimeng]#gccfork1.c-ofork1

[root@lwm

liweimeng]#./fork1

Iamthechildprocess,IDis4238

Iamtheparentprocess,IDis4237因?yàn)閒ork()函數(shù)用于從已存在的進(jìn)程中創(chuàng)建一個(gè)新的子進(jìn)程,在pid=fork();語(yǔ)句之前只有父進(jìn)程在運(yùn)行,而在之后,父進(jìn)程和新創(chuàng)建的子進(jìn)程都在運(yùn)行,子進(jìn)程拷貝父進(jìn)程的代碼段,所以子進(jìn)程中同樣有

if(pid<0)printf("errorinfork!");

elseif(pid==0)

printf("Iamthechildprocess,IDis%d\n",getpid());

else

printf("Iamtheparentprocess,IDis%d\n",getpid());2.進(jìn)程控制-進(jìn)程的創(chuàng)建#include<unistd.h>#include<unistd.h>intmain(){

pid_t

pid;

Intcount=0;

pid=fork();

Count++;

Printf(“count=%d\n”,count);Return0;}輸出:Count=1Count=1拷貝數(shù)據(jù)段的實(shí)例將被父子進(jìn)程各執(zhí)行一次,但是子進(jìn)程執(zhí)行時(shí)使自己的數(shù)據(jù)段里面的(這個(gè)數(shù)據(jù)段是從父進(jìn)程那copy過(guò)來(lái)的一模一樣)count+1,同樣父進(jìn)程執(zhí)行時(shí)使自己的數(shù)據(jù)段里面count+1,互不影響2.進(jìn)程控制-進(jìn)程的創(chuàng)建vfork的作用和fork基本相同,區(qū)別在于:vfork并不完全復(fù)制父進(jìn)程的數(shù)據(jù)段,而是和父進(jìn)程共享數(shù)據(jù)段。調(diào)用vfork對(duì)于父子進(jìn)程的執(zhí)行次序有所限制。調(diào)用vfork函數(shù)將使父進(jìn)程掛起,直至子進(jìn)程返回。vfork

保證子進(jìn)程先運(yùn)行,在她調(diào)用exec或exit之后父進(jìn)程才可能被調(diào)度運(yùn)行。#include<unistd.h>

#include<stdio.h>

#include<sys/types.h>

int

main(void)

{

pid_t

pid;

intcount=0;

pid=vfork();

if(pid==0)

{

count++;

_exit(0);}

else

count++;

printf("count=%d\n",count);return0;

}2.進(jìn)程控制-進(jìn)程的創(chuàng)建在子進(jìn)程調(diào)用exec或exit之前與父進(jìn)程數(shù)據(jù)是共享的,所以子進(jìn)程退出后把父進(jìn)程的數(shù)據(jù)段count改成1了,子進(jìn)程退出后,父進(jìn)程又執(zhí)行,最終就將count變成了2運(yùn)行結(jié)果:

[root@lwm

liweimeng]#gccfork2.c-ofork2

[root@lwm

liweimeng]#./fork2

count=22.進(jìn)程控制-進(jìn)程的創(chuàng)建(2)創(chuàng)建執(zhí)行其他程序的進(jìn)程使用exec族的函數(shù)執(zhí)行新的程序,以新的子進(jìn)程完全替代原有的進(jìn)程。int

execl(constchar*pathname,constchar*arg,…);int

execlp(constchar*filename,conxtchar*arg,…);int

execle(constchar*pathname,conxtchar*arg,…,char#constencp[]);int

execv(constchar*pathname,char*constargv[]);int

execvp(constchar*filename,char*constargv[]);int

execve(constchar*pathname,char*constargv[],char*constenvp[]);2.進(jìn)程控制-進(jìn)程的創(chuàng)建exec函數(shù)族的特點(diǎn)用于啟動(dòng)一個(gè)指定路徑和文件名的進(jìn)程。某進(jìn)程一旦調(diào)用了exec類函數(shù),正在執(zhí)行的程序結(jié)束,系統(tǒng)把代碼段換成新的程序的代碼,原有的數(shù)據(jù)段和堆棧段也被放棄,新的數(shù)據(jù)段和堆棧段被分配,但是進(jìn)程號(hào)被保留。結(jié)果為:系統(tǒng)認(rèn)為正在執(zhí)行的還是原來(lái)的進(jìn)程,但是進(jìn)程對(duì)應(yīng)的程序被替換了。2.進(jìn)程控制-進(jìn)程的創(chuàng)建fork和exec搭配實(shí)現(xiàn)讓父進(jìn)程的代碼執(zhí)行又啟動(dòng)一個(gè)新的指定的進(jìn)程。execl()使用范例#include<stdio.h>#include<unistd.h>#include<sys/types.h>main(){

pid_t

pid;

printf("Nowonlyoneprocess\n");

printf("Callingfork...\n");

pid=fork();

if(pid==0)/*進(jìn)程為子進(jìn)程*/{

printf("Iamthechild\n");

execl("/bin/ls","-l",NULL);

/*如果execl返回,說(shuō)明調(diào)用失敗*/

perror("execlfailedtorunls");exit(1);}2.進(jìn)程控制-進(jìn)程的創(chuàng)建elseif(pid>0)/*進(jìn)程為父進(jìn)程*/ {

printf("I'mtheparent,mychild'spidis%d\n",pid);

execl("/bin/ps","-c",NULL);/*如果execl返回,說(shuō)明調(diào)用失敗*/

perror("execlfailedtorunls");exit(1);}else

printf("Forkfall!\n");}2.進(jìn)程控制-進(jìn)程的創(chuàng)建Clone此函數(shù)是fork的變形,對(duì)父子進(jìn)程的共享資源提供了更多的控制。可以使得創(chuàng)建的子進(jìn)程共享父進(jìn)程的資源。函數(shù)原型:int

clone(int(*fn)(void),void*child_stack,int

flags,void*arg)fn是函數(shù)指針,指向要執(zhí)行的函數(shù)child_stack子進(jìn)程堆棧段的指針flags用于不同繼承內(nèi)容的標(biāo)識(shí)2.進(jìn)程控制-進(jìn)程的創(chuàng)建Flags標(biāo)識(shí)含義CLONE_VM繼承父進(jìn)程的虛擬存儲(chǔ)器屬性CLONE_FS繼承父進(jìn)程的chroot

chdir

和umaskCLONE_FILES繼承父進(jìn)程的文件描述符CLONE_PID繼承父進(jìn)程的文件鎖、進(jìn)程號(hào)及時(shí)間片CLONE_SIGHAND繼承父進(jìn)程的信號(hào)處理程序Flags標(biāo)識(shí)的選取2.進(jìn)程控制-進(jìn)程的創(chuàng)建intvariable,fd;

int

do_something(){

variable=42;

close(fd);

_exit(0);

}

2.進(jìn)程控制-進(jìn)程的創(chuàng)建int

main(int

argc,char*argv[]){

void**child_stack;

chartempch;

variable=9;

fd=open("test.file",O_RDONLY);

child_stack=(void**)malloc(16384);

printf("Thevariablewas%d\n",variable);

clone(do_something,child_stack,CLONE_VM|CLONE_FILES,NULL);

sleep(1);/*延時(shí)以便子進(jìn)程完成關(guān)閉文件操作、修改變量*/

2.進(jìn)程控制-進(jìn)程的創(chuàng)建printf("Thevariableisnow%d\n",variable);

if(read(fd,&tempch,1)<1){

perror("FileReadError");

exit(1);

}

printf("Wecouldreadfromthefile\n");

return0;

}2.進(jìn)程控制-進(jìn)程的創(chuàng)建運(yùn)行輸出:

Thevariableisnow42

FileReadError

程序的輸出結(jié)果說(shuō)明,子進(jìn)程將文件關(guān)閉并將變量修改(調(diào)用clone時(shí)用到的CLONE_VM、CLONE_FILES標(biāo)志將使得變量和文件描述符表被共享),父進(jìn)程隨即就感覺(jué)到了,這就是clone的特點(diǎn)。

2.進(jìn)程控制-進(jìn)程的掛起Sleep函數(shù)調(diào)用sleep可以用來(lái)使進(jìn)程掛起指定的秒數(shù)。如果指定的掛起的時(shí)間到了,該調(diào)用的返回值為0;如果該函數(shù)調(diào)用被信號(hào)打斷,則返回剩余掛起的時(shí)間數(shù)(指定的時(shí)間減去已經(jīng)掛起的時(shí)間)函數(shù)原型unsignedint

sleep(unsigned

intseconds)2.進(jìn)程控制-進(jìn)程的等待WaitWait的作用是為發(fā)出調(diào)用的進(jìn)程只要有子進(jìn)程,就睡眠到他們中的一個(gè)終止為止。函數(shù)原型pid_t

wait(int*status);

//子進(jìn)程的結(jié)束狀態(tài)值會(huì)由參數(shù)status返回

pid_t

waitpid(pid_t

溫馨提示

  • 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. 人人文庫(kù)網(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ì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論