版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)
文檔簡介
1、第四章 UNIX下的C語言開發(fā)環(huán)境,,6.1 程序設(shè)計環(huán)境,學習程序設(shè)計從程序語言開始,但還應(yīng)了解程序執(zhí)行和程序與外界的交互問題。,1.理想態(tài)的程序運行環(huán)境,,用戶程序直接控制和使用各種設(shè)備,完成各種操作。,針對一個簡單程序:,main(){ int c; while ( ( c=getchar()) != EOF )putchar(c);},,認為執(zhí)行過程為:,在單用戶單任務(wù)環(huán)境中基本符合。,2.
2、多任務(wù)環(huán)境下程序執(zhí)行,多任務(wù)中每一時刻都會有多個用戶程序提出訪問請求,因此會有:,,如此混亂的情況,程序?qū)o法運行。,為使多道環(huán)境中的程序正確執(zhí)行,需要OS管理。,,用戶程序需要系統(tǒng)核心區(qū)程序的管理,達到各自任務(wù)的執(zhí)行。,6.2 基于系統(tǒng)支持的程序設(shè)計,,1. 建立系統(tǒng)編程的思想,理解多道環(huán)境程序執(zhí)行狀況,轉(zhuǎn)換用戶程序是執(zhí)行主體的認識。 了解OS可提供的服務(wù)及服務(wù)方式。 充分利用OS提供服務(wù)功能解決實際問題。 盡量使編寫的程序最大
3、限度的滿足系統(tǒng)平臺的支持能力。,1. gcc 與 gdb,1.1 UNIX和C語言C 是一種在 UNIX 操作系統(tǒng)的早期就被廣泛使用的通用編程語言,它最早是由貝爾實驗室的 Dennis Ritchie 為了 UNIX 的輔助開發(fā)而寫的。C 是所有版本的UNIX上的系統(tǒng)語言。幾乎任何一種計算機上都有至少一種能用的 C 編譯器
4、; 并且它的語法和函數(shù)庫在不同的平臺上都是統(tǒng)一的。80年代末期美國國家標準協(xié)會 (American National Standards Institute)發(fā)布了一個被稱為 ANSI C 的 C 語言標準,這保證了在不同平臺上的C的一致性。,7,1. gcc 與 gdb,1.2 GNU C編譯器GNU C 編譯
5、器(gcc)是一個全功能的 ANSI C 兼容編譯器,它是所有UNIX系統(tǒng)可用的C編譯器。gcc是可以在多種硬體平臺上編譯出可執(zhí)行程序的超級編譯器,其執(zhí)行效率與一般的編譯器相比平均效率要高20%~30%。,8,3.1 LINUX下C語言編程概述,1. gcc 與 gdb,gcc編譯過程:預(yù)處理,對源代碼文件中的文件包含(include)、預(yù)編譯語句(如宏定義define等)進行分析。編譯,就是把C
6、/C++代碼“翻譯”成匯編代碼。匯編,將第二步輸出的匯編代碼翻譯成符合一定格式的機器代碼,生成以.o為后綴的目標文件。鏈接,將上步生成的目標文件和系統(tǒng)庫的目標文件和庫文件鏈接起來,最終生成了可以在特定平臺運行的可執(zhí)行文件。,10,1. Gcc編譯流程解析如本章開頭提到的,Gcc的編譯流程分為了4個步驟,分別為:· 預(yù)處理(Pre-Processing);· 編譯(Compiling);· 匯編(
7、Assembling);· 鏈接(Linking)。下面就具體來查看一下Gcc是如何完成4 個步驟的。首先,有以下hello.c源代碼:#includeint main(){printf("Hello! This is our embedded world!\n");return 0;},3.3 Gcc編譯器,(1)預(yù)處理階段在該階段,編譯器將上述代碼中的stdio.h編譯進來,并且用戶
8、可以使用Gcc的選項“-E”進行查看,該選項的作用是讓Gcc在預(yù)處理結(jié)束后停止編譯過程。[root@localhost Gcc]# Gcc –E hello.c –o hello.i在此處,選項“-o”是指目標文件,由上表可知,“.i”文件為已經(jīng)過預(yù)處理的C 原始程序。以下列出了hello.i文件的部分內(nèi)容:typedef int (*__gconv_trans_fct) (struct __gconv_step *,struc
9、t __gconv_step_data *, void *,__const unsigned char *,__const unsigned char **,__const unsigned char *, unsigned char **,size_t *);…,,# 2 "hello.c" 2int main(){printf("Hello! This is our embedded w
10、orld!\n");return 0;}由此可見,Gcc確實進行了預(yù)處理,它把“stdio.h”的內(nèi)容插入到hello.i文件中。,(2)編譯階段接下來進行的是編譯階段,在這個階段中,Gcc 首先要檢查代碼的規(guī)范性、是否有語法錯誤等,以確定代碼的實際要做的工作,在檢查無誤后,Gcc 把代碼翻譯成匯編語言。用戶可以使用“-S”選項來進行查看,該選項只進行編譯而不進行匯編,生成匯編代碼。[root@localhost G
11、cc]# Gcc –S hello.i –o hello.s以下列出了hello.s的內(nèi)容,可見Gcc已經(jīng)將其轉(zhuǎn)化為匯編了,感興趣的讀者可以分析一下這一行簡單的C語言小程序是如何用匯編代碼實現(xiàn)的。.file "hello.c“.section .rodata.align 4.LC0:.string "Hello! This is our embedded world!".text.globl
12、 main.type main, @functionmain:pushl %ebpmovl %esp, %ebpsubl $8, %espandl $-16, %espmovl $0, %eaxaddl $15, %eax.section .note.GNU-stack,"",@progbits,(3)匯編階段匯編階段是把編譯階段生成的“.s”文件轉(zhuǎn)成目標文件,讀者在此可使用選項“-c”就可看到
13、匯編代碼已轉(zhuǎn)化為“.o”的二進制目標代碼了。如下所示:[root@localhost Gcc]# Gcc –c hello.s –o hello.o,Gcc編譯器,(4)鏈接階段在成功編譯之后,就進入了鏈接階段。在這里涉及到一個重要的概念:函數(shù)庫。讀者可以重新查看這個小程序,在這個程序中并沒有定義“printf”的函數(shù)實現(xiàn),且在預(yù)編譯中包含進的“stdio.h”中也只有該函數(shù)的聲明,而沒有定義函數(shù)的實現(xiàn),那么,是在哪里實現(xiàn)“prin
14、tf”函數(shù)的呢?最后的答案是:系統(tǒng)把這些函數(shù)實現(xiàn)都被做到名為libc.so.6的庫文件中去了,在沒有特別指定時,Gcc 會到系統(tǒng)默認的搜索路徑“/usr/lib”下進行查找,也就是鏈接到libc.so.6庫函數(shù)中去,這樣就能實現(xiàn)函數(shù)“printf”了,而這也就是鏈接的作用。函數(shù)庫一般分為靜態(tài)庫和動態(tài)庫兩種。靜態(tài)庫是指編譯鏈接時,把庫文件的代碼全部加入到可執(zhí)行文件中,因此生成的文件比較大,但在運行時也就不再需要庫文件了。其后綴名一般為“.
15、a”。動態(tài)庫與之相反,在編譯鏈接時并沒有把庫文件的代碼加入到可執(zhí)行文件中,而是在程序執(zhí)行時由運行時鏈接文件加載庫,這樣可以節(jié)省系統(tǒng)的開銷。動態(tài)庫一般后綴名為“.so”,如前面所述的libc.so.6就是動態(tài)庫。Gcc在編譯時默認使用動態(tài)庫。完成了鏈接之后,Gcc就可以生成可執(zhí)行文件,如下所示。[root@localhost Gcc]# Gcc hello.o –o hello運行該可執(zhí)行文件,出現(xiàn)正確的結(jié)果如下。[root@loc
16、alhost Gcc]# ./helloHello! This is our embedded world!,Gcc編譯選項:,Gcc編譯器,1. UNIX下的C語言開發(fā)環(huán)境,gcc遵循的文件類型規(guī)定 .c為后綴的文件,C語言源代碼文件; .a為后綴的文件,是由目標文件構(gòu)成的檔案庫文件; .C,.cc或.cxx 為后綴的文件,是C++源代碼文件; .h為后綴的文件,是程序所包含的頭文件;.i 為后綴的文件,是已經(jīng)預(yù)處理過的C
17、源代碼文件;.ii為后綴的文件,是已經(jīng)預(yù)處理過的C++源代碼文件;.m為后綴的文件,是Objective-C源代碼文件; .o為后綴的文件,是編譯后的目標文件; .s為后綴的文件,是匯編語言源代碼文件;.S為后綴的文件,是經(jīng)過預(yù)編譯的匯編語言源代碼文件。,18,頭文件,頭文件是用來提供常量的定義和系統(tǒng)和函數(shù)調(diào)用的聲明,這些頭文件通常放在/usr/include和其子目錄中。根據(jù)不同的Linux版本,頭文件可能放在/usr/in
18、clude/sys和/usr/include/linux.#include ,庫函數(shù),庫函數(shù)是一些預(yù)先編譯好的函數(shù)的集合,這些函數(shù)可以有很好的重用性。通常來講,它們包含有相關(guān)的函數(shù)集合來完成一項常用任務(wù)。典型的庫函數(shù)有屏幕處理函數(shù) (curses和ncurses庫)和數(shù)據(jù)庫訪問函數(shù)(dbm庫)。標準系統(tǒng)函數(shù)通常存放在/lib和/usr/lib中。C編譯器需要被告知搜索哪個庫,否則缺省情況下只搜索標準庫。傳統(tǒng)靜態(tài)庫 .a E
19、xamples are /usr/lib/libc.a and /usr/X11/lib/libX11.a for the standard C library and the X11 library共享庫 .so On a typical Linux system, the shared version of the standard math library is /usr/lib/libm.so,1. g
20、cc 與 gdb,1.5 gdb調(diào)試和分析選項gdb 基本命令file 裝入想要調(diào)試的可執(zhí)行文件;kill 終止正在調(diào)試的程序;list 列出產(chǎn)生執(zhí)行文件的源代碼的一部分;next 執(zhí)行一行源代碼但不進入函數(shù)內(nèi)部;step 執(zhí)行一行源代碼而且進入函數(shù)內(nèi)部;run 執(zhí)行當前被調(diào)試的程序;quit 終止 gdb ;watch
21、 使你能監(jiān)視一個變量的值而不管它何時被改變;break 在代碼里設(shè)置斷點, 這將使程序執(zhí)行到這里時被掛起;make 使你能不退出 gdb 就可以重新產(chǎn)生可執(zhí)行文件;shell 使你能不離開 gdb 就執(zhí)行 UNIX shell 命令.,21,1. gcc 與 gdb,gdb調(diào)試舉例,/* gdbtest.c */
22、#include int sum(int m);int main(int argc, char **argv){int i, n = 0;sum(50);for(i=1; i<=50; i++){n += i;}printf(“The sum of 1-50 is %d\n”, n);},int sum(int m){int i, n = 0;for(i=1; i<=m; i++)
23、{n += i;}printf(“The sum of 1-%d is %d\n”, m, n);},例:$ gcc -Wall -g gdbtest.c -o gdbtest,22,1. gcc 與 gdb,1. 啟動gdb開始調(diào)試,例1:$ gdb gdbtest,例2:$ gdb(gdb) file gdbtest,23,1. gcc 與 gdb,2. 在gdb中查看源代碼,例:(gdb) list,li
24、st也可以縮寫為l,24,1. gcc 與 gdb,3. 在gdb中設(shè)置斷點,例1:(gdb) break 9,break也可以縮寫為b,注意:在gdb中利用行號設(shè)置斷點,是指代碼運行到對應(yīng)行號之前暫停;gdb中可以設(shè)置多個斷點。,25,1. gcc 與 gdb,3. 在gdb中設(shè)置斷點,例2:(gdb) break sum,設(shè)置函數(shù)斷點,在函數(shù)體開始處,例3:(gdb) break 10 if i==10,設(shè)置條件斷點,26,
25、1. gcc 與 gdb,4. 開看斷點情況,例:(gdb) info break,27,1. gcc 與 gdb,5. 運行代碼,例:(gdb) run,run也可以縮寫為r,28,1. gcc 與 gdb,6. 查看變量,例:(gdb) print i,print也可以縮寫為p;i為變量名,“$N”是當前變量值的引用標記,29,1. gcc 與 gdb,7. 單步運行,單步運行可以使用命令“step”和“next”,它們之間的
26、區(qū)別在于:若有函數(shù)調(diào)用的時候“step”會進入函數(shù)體,而“next”不會進入該函數(shù);,8. 恢復(fù)程序運行,使用命令“continue”可以恢復(fù)程序正常運行,直到遇到下一個斷點或者到程序結(jié)束;,gdb中程序有“運行”、“暫?!焙汀巴V埂比N狀態(tài)?!皶和!睜顟B(tài)時,函數(shù)的地址、參數(shù)、局部變量都被壓入“棧”中,故可以查看函數(shù)的各種屬性;函數(shù)處于“停止”狀態(tài)時,“?!睍詣映蜂N,也就無法查看函數(shù)的信息了。,30,2. make工程管理器,2.1
27、為什么要使用make?工作量問題:對于擁有多個(上百個)源文件的軟件項目,只需編寫一次編譯過程,而不需要在每次源文件修改后重復(fù)輸入眾多的文件名和編譯命令進行編譯;效率問題:make能夠根據(jù)文件的時間戳自動發(fā)現(xiàn)更新過的源文件,并通過讀入Makefile文件來對更新的源文件進行編譯而對其它文件只進行鏈接操作。,31,2. make命令,2.2 Makefile的格式Makefile是make讀入的唯一配置文件,Makefile文件
28、通常包含如下內(nèi)容:需要由make創(chuàng)建的目標體(target),通常是目標文件或可執(zhí)行文件;要創(chuàng)建的目標體所依賴的文件(dependency_file);創(chuàng)建每個目標體時需要運行的命令(commmand)。,Makefile格式:target: dependency_file command,command之前必須有個“tab”,32,4. 鏈接特殊函數(shù)庫,/*filename is temp.c */
29、# include int main(int argc,char *argv) { double value; value=log(argc); printf("Value:%f \n",value); } 用命令:gcc –o temp temp.c 編譯時出錯。修改命令: gcc –o temp temp.c –lm這里指明編譯時與數(shù)學庫libm.a相鏈接,則可正
溫馨提示
- 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. 眾賞文庫僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
- 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
評論
0/150
提交評論