Linux下C編程基礎(chǔ)之:gcc編譯器
掃描二維碼
隨時(shí)隨地手機(jī)看文章
GNUCC(簡(jiǎn)稱(chēng)為gcc)是GNU項(xiàng)目中符合ANSIC標(biāo)準(zhǔn)的編譯系統(tǒng),能夠編譯用C、C++和ObjectC等語(yǔ)言編寫(xiě)的程序。gcc不僅功能強(qiáng)大,而且可以編譯如C、C++、ObjectC、Java、Fortran、Pascal、Modula-3和Ada等多種語(yǔ)言,而且gcc是一個(gè)交叉平臺(tái)編譯器,它能夠在當(dāng)前CPU平臺(tái)上為多種不同體系結(jié)構(gòu)的硬件平臺(tái)開(kāi)發(fā)軟件,因此尤其適合在嵌入式領(lǐng)域的開(kāi)發(fā)編譯。本章中的示例,除非特別注明,否則均采用4.x.x的gcc版本。
表3.6所示為gcc支持編譯源文件的后綴及其解釋。
表3.6 gcc所支持后綴名解釋
后綴名
所對(duì)應(yīng)的語(yǔ)言
后綴名
所對(duì)應(yīng)的語(yǔ)言
.c
C原始程序
.s/.S
匯編語(yǔ)言原始程序
.C/.cc/.cxx
C++原始程序
.h
預(yù)處理文件(頭文件)
.m
Objective-C原始程序
.o
目標(biāo)文件
.i
已經(jīng)過(guò)預(yù)處理的C原始程序
.a/.so
編譯后的庫(kù)文件
.ii
已經(jīng)過(guò)預(yù)處理的C++原始程序
…
…
3.3.1gcc編譯流程解析如本章開(kāi)頭提到的,gcc的編譯流程分為了4個(gè)步驟,分別為:
n 預(yù)處理(Pre-Processing);
n 編譯(Compiling);
n 匯編(Assembling);
n 鏈接(Linking)。
下面就具體來(lái)查看一下gcc是如何完成以上4個(gè)步驟的。
首先看一下hello.c的源代碼:
#include<stdio.h>
intmain()
{
printf("Hello!Thisisourembeddedworld!\n");
return0;
}
(1)預(yù)處理階段。
在該階段,對(duì)包含的頭文件(#include)和宏定義(#define、#ifdef等)進(jìn)行處理。在上述代碼的預(yù)處理過(guò)程中,編譯器將包含的頭文件stdio.h編譯進(jìn)來(lái),并且用戶可以使用gcc的選項(xiàng)“-E”進(jìn)行查看,該選項(xiàng)的作用是讓gcc在預(yù)處理結(jié)束后停止編譯過(guò)程。
注意
gcc指令的一般格式為:gcc[選項(xiàng)]要編譯的文件[選項(xiàng)][目標(biāo)文件]
其中,目標(biāo)文件可缺省,gcc默認(rèn)生成可執(zhí)行的文件,名為:編譯文件.out
[root@localhostgcc]#gcc–Ehello.c–ohello.i
在此處,選項(xiàng)“-o”是指目標(biāo)文件,由表3.6可知,“.i”文件為已經(jīng)過(guò)預(yù)處理的C程序。以下列出了hello.i文件的部分內(nèi)容:
typedefint(*__gconv_trans_fct)(struct__gconv_step*,
struct__gconv_step_data*,void*,
__constunsignedchar*,
__constunsignedchar**,
__constunsignedchar*,unsignedchar**,
size_t*);
…
#2"hello.c"2
intmain()
{
printf("Hello!Thisisourembeddedworld!\n");
return0;
}
由此可見(jiàn),gcc確實(shí)進(jìn)行了預(yù)處理,它把“stdio.h”的內(nèi)容插入hello.i文件中。
(2)編譯階段。
接下來(lái)進(jìn)行的是編譯階段,在這個(gè)階段中,gcc首先要檢查代碼的規(guī)范性、是否有語(yǔ)法錯(cuò)誤等,以確定代碼實(shí)際要做的工作,在檢查無(wú)誤后,gcc把代碼翻譯成匯編語(yǔ)言。用戶可以使用“-S”選項(xiàng)來(lái)進(jìn)行查看,該選項(xiàng)只進(jìn)行編譯而不進(jìn)行匯編,結(jié)果生成匯編代碼。
[root@localhostgcc]#gcc–Shello.i–ohello.s
以下列出了hello.s的內(nèi)容,可見(jiàn)gcc已經(jīng)將其轉(zhuǎn)化為匯編代碼了,感興趣的讀者可以分析一下這一個(gè)簡(jiǎn)單的C語(yǔ)言小程序是如何用匯編代碼實(shí)現(xiàn)的。
.file"hello.c"
.section.rodata
.align4
.LC0:
.string"Hello!Thisisourembeddedworld!"
.text
.globlmain
.typemain,@function
main:
pushl%ebp
movl%esp,%ebp
subl$8,%esp
andl$-16,%esp
movl$0,%eax
addl$15,%eax
addl$15,%eax
shrl$4,%eax
sall$4,%eax
subl%eax,%esp
subl$12,%esp
pushl$.LC0
callputs
addl$16,%esp
movl$0,%eax
leave
ret
.sizemain,.-main
.ident"GCC:(GNU)4.0.0200XYZ19(RedHat4.0.0-8)"
.section.note.GNU-stack,"",@progbits
(3)匯編階段。
匯編階段是把編譯階段生成的“.s”文件轉(zhuǎn)成目標(biāo)文件,讀者在此使用選項(xiàng)“-c”就可看到匯編代碼已轉(zhuǎn)化為“.o”的二進(jìn)制目標(biāo)代碼了,如下所示:
[root@localhostgcc]#gcc–chello.s–ohello.o
(4)鏈接階段。
在成功編譯之后,就進(jìn)入了鏈接階段。這里涉及一個(gè)重要的概念:函數(shù)庫(kù)。
讀者可以重新查看這個(gè)小程序,在這個(gè)程序中并沒(méi)有定義“printf”的函數(shù)實(shí)現(xiàn),且在預(yù)編譯中包含進(jìn)的“stdio.h”中也只有該函數(shù)的聲明,而沒(méi)有定義函數(shù)的實(shí)現(xiàn),那么,是在哪里實(shí)現(xiàn)“printf”函數(shù)的呢?最后的答案是:系統(tǒng)把這些函數(shù)的實(shí)現(xiàn)都放到名為libc.so.6的庫(kù)文件中去了,在沒(méi)有特別指定時(shí),gcc會(huì)到系統(tǒng)默認(rèn)的搜索路徑“/usr/lib”下進(jìn)行查找,也就是鏈接到libc.so.6函數(shù)庫(kù)中去,這樣就能調(diào)用函數(shù)“printf”了,而這也正是鏈接的作用。
函數(shù)庫(kù)有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)兩種。靜態(tài)庫(kù)是指編譯鏈接時(shí),將庫(kù)文件的代碼全部加入可執(zhí)行文件中,因此生成的文件比較大,但在運(yùn)行時(shí)也就不再需要庫(kù)文件了。其后綴名通常為“.a”。動(dòng)態(tài)庫(kù)與之相反,在編譯鏈接時(shí)并沒(méi)有將庫(kù)文件的代碼加入可執(zhí)行文件中,而是在程序執(zhí)行時(shí)加載庫(kù),這樣可以節(jié)省系統(tǒng)的開(kāi)銷(xiāo)。一般動(dòng)態(tài)庫(kù)的后綴名為“.so”,如前面所述的libc.so.6就是動(dòng)態(tài)庫(kù)。gcc在編譯時(shí)默認(rèn)使用動(dòng)態(tài)庫(kù)。
完成了鏈接之后,gcc就可以生成可執(zhí)行文件,如下所示。
[root@localhostgcc]#gcchello.o–ohello
運(yùn)行該可執(zhí)行文件,出現(xiàn)的正確結(jié)果如下。
[root@localhostgcc]#./hello
Hello!Thisisourembeddedworld!
3.3.2gcc編譯選項(xiàng)分析gcc有超過(guò)100個(gè)可用選項(xiàng),主要包括總體選項(xiàng)、告警和出錯(cuò)選項(xiàng)、優(yōu)化選項(xiàng)和體系結(jié)構(gòu)相關(guān)選項(xiàng)。以下對(duì)每一類(lèi)中最常用的選項(xiàng)進(jìn)行講解。
(1)常用選項(xiàng)。
gcc的常用選項(xiàng)如表3.7所示,很多在前面的示例中已經(jīng)有所涉及。
表3.7 gcc常用選項(xiàng)列表
選項(xiàng)
含義
-c
只編譯不鏈接,生成目標(biāo)文件“.o”
-S
只編譯不匯編,生成匯編代碼
-E
只進(jìn)行預(yù)編譯,不做其他處理
-g
在可執(zhí)行程序中包含標(biāo)準(zhǔn)調(diào)試信息
-ofile
將file文件指定為輸出文件
-v
打印出編譯器內(nèi)部編譯各過(guò)程的命令行信息和編譯器的版本
-Idir
在頭文件的搜索路徑列表中添加dir目錄
前一小節(jié)已經(jīng)講解了“-c”、“-E”、“-o”、“-S”選項(xiàng)的使用方法,在此主要講解另外2個(gè)非常常用的庫(kù)依賴選項(xiàng)“-Idir”。
n “-Idir”
正如上表中所述,“-Idir”選項(xiàng)可以在頭文件的搜索路徑列表中添加dir目錄。由于Linux中頭文件都默認(rèn)放到了“/usr/include/”目錄下,因此,當(dāng)用戶希望添加放置在其他位置的頭文件時(shí),就可以通過(guò)“-Idir”選項(xiàng)來(lái)指定,這樣,gcc就會(huì)到相應(yīng)的位置查找對(duì)應(yīng)的目錄。
比如在“/root/workplace/gcc”下有兩個(gè)文件:
/*hello1.c*/
#include<my.h>
intmain()
{
printf("Hello!!\n");
return0;
}
/*my.h*/
#include<stdio.h>
這樣,就可在gcc命令行中加入“-I”選項(xiàng):
[root@localhostgcc]gcchello1.c–I/root/workplace/gcc/-ohello1
這樣,gcc就能夠執(zhí)行出正確結(jié)果。
小知識(shí)
在include語(yǔ)句中,“<>”表示在標(biāo)準(zhǔn)路徑中搜索頭文件,““””表示在本目錄中搜索。故在上例中,可把hello1.c的“#include<my.h>”改為“#include“my.h””,就不需要加上“-I”選項(xiàng)了。
(2)庫(kù)選項(xiàng)。
gcc庫(kù)選項(xiàng)如表3.8所示。
表3.8 gcc庫(kù)選項(xiàng)列表
選項(xiàng)
含義
-static
進(jìn)行靜態(tài)編譯,即鏈接靜態(tài)庫(kù),禁止使用動(dòng)態(tài)庫(kù)
-shared
1.可以生成動(dòng)態(tài)庫(kù)文件
2.進(jìn)行動(dòng)態(tài)編譯,盡可能地鏈接動(dòng)態(tài)庫(kù),只有當(dāng)沒(méi)有動(dòng)態(tài)庫(kù)時(shí)才會(huì)鏈接同名的靜態(tài)庫(kù)(默認(rèn)選項(xiàng),即可省略)
-Ldir
在庫(kù)文件的搜索路徑列表中添加dir目錄
-lname
鏈接稱(chēng)為libname.a(靜態(tài)庫(kù))或者libname.so(動(dòng)態(tài)庫(kù))的庫(kù)文件。若兩個(gè)庫(kù)都存在,則根據(jù)編譯方式(-static還是-shared)而進(jìn)行鏈接
-fPIC(或-fpic)
生成使用相對(duì)地址的位置無(wú)關(guān)的目標(biāo)代碼(PositionIndependentCode)。然后通常使用gcc的-static選項(xiàng)從該P(yáng)IC目標(biāo)文件生成動(dòng)態(tài)庫(kù)文件
我們通常需要將一些常用的公共函數(shù)編譯并集成到二進(jìn)制文件(Linux的ELF格式文件),以便其他程序可重復(fù)地使用該文件中的函數(shù),此時(shí)將這種文件叫做函數(shù)庫(kù),使用函數(shù)庫(kù)不僅能夠節(jié)省很多內(nèi)存和存儲(chǔ)器的空間資源,而且更重要的是大大降低開(kāi)發(fā)難度和開(kāi)銷(xiāo),提高開(kāi)發(fā)效率并增強(qiáng)程序的結(jié)構(gòu)性。實(shí)際上,在Linux中的每個(gè)程序都會(huì)鏈接到一個(gè)或者多個(gè)庫(kù)。比如使用C函數(shù)的程序會(huì)鏈接到C運(yùn)行時(shí)庫(kù),Qt應(yīng)用程序會(huì)鏈接到Qt支持的相關(guān)圖形庫(kù)等。
函數(shù)庫(kù)有靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)兩種,靜態(tài)庫(kù)是一系列的目標(biāo)文件(.o文件)的歸檔文件(文件名格式為libname.a),如果在編譯某個(gè)程序時(shí)鏈接靜態(tài)庫(kù),則鏈接器將會(huì)搜索靜態(tài)庫(kù),從中提取出它所需要的目標(biāo)文件并直接復(fù)制到該程序的可執(zhí)行二進(jìn)制文件(ELF格式文件)之中;動(dòng)態(tài)庫(kù)(文件名格式為libname.so[.主版本號(hào).次版本號(hào).發(fā)行號(hào)])在程序編譯時(shí)并不會(huì)被鏈接到目標(biāo)代碼中,而是在程序運(yùn)行時(shí)才被載入。
下面舉一個(gè)簡(jiǎn)單的例子,講解如何怎么創(chuàng)建和使用這兩種函數(shù)庫(kù)。
首先創(chuàng)建unsgn_pow.c文件,它包含unsgn_pow()函數(shù)的定義,具體代碼如下所示。
/*unsgn_pow.c:庫(kù)程序*/
unsignedlonglongunsgn_pow(unsignedintx,unsignedinty)
{
unsignedlonglongres=1;
if(y==0)
{
res=1;
}
elseif(y==1)
{
res=x;
}
else
{
res=x*unsgn_pow(x,y-1);
}
returnres;
}
然后創(chuàng)建pow_test.c文件,它會(huì)調(diào)用unsgn_pow()函數(shù)。
/*pow_test.c*/
#include<stdio.h>
#include<stdlib.h>
intmain(intargc,char*argv[])
{
unsignedintx,y;
unsignedlonglongres;
if((argc<3)||(sscanf(argv[1],"%u",&x)!=1)
||(sscanf(argv[2],"%u",&y))!=1)
{
printf("Usage:powbaseexponent\n");
exit(1);
}
res=unsgn_pow(x,y);
printf("%u^%u=%u\n",x,y,res);
exit(0);
}
我們用unsgn_pow.c文件可以制作一個(gè)函數(shù)庫(kù)。下面分別講解怎么生成靜態(tài)庫(kù)和動(dòng)態(tài)庫(kù)。
n 靜態(tài)庫(kù)的創(chuàng)建和使用。
創(chuàng)建靜態(tài)庫(kù)比較簡(jiǎn)單,使用歸檔工具ar將一些目標(biāo)文件集成在一起。
[root@localhostlib]#gcc-cunsgn_pow.c
[root@localhostlib]#arrcsvlibpow.aunsgn_pow.o
a-unsgn_pow.o
下面編譯主程序,它將會(huì)鏈接到剛生成的靜態(tài)庫(kù)libpow.a。具體運(yùn)行結(jié)果如下所示。
[root@localhostlib]#gcc-opow_testpow_test.c-L.–lpow
[root@localhostlib]#./pow_test210
2^10=1024
其中,選項(xiàng)“-Ldir”的功能與“-Idir”類(lèi)似,能夠在庫(kù)文件的搜索路徑列表中添加dir目錄,而“-lname”選項(xiàng)指示編譯時(shí)鏈接到庫(kù)文件libname.a或者libname.so。本實(shí)例中,程序pow_test.c需要使用當(dāng)前目錄下的一個(gè)靜態(tài)庫(kù)libpow.a。
n 動(dòng)態(tài)庫(kù)的創(chuàng)建和使用。
首先使用gcc的-fPIC選項(xiàng)為動(dòng)態(tài)庫(kù)構(gòu)造一個(gè)目標(biāo)文件
[root@localhostlib]#gcc-fPIC-Wall-cunsgn_pow.c
接下來(lái),使用-shared選項(xiàng)和已創(chuàng)建的位置無(wú)關(guān)目標(biāo)代碼,生成一個(gè)動(dòng)態(tài)庫(kù)libpow.so。
[root@localhostlib]#gcc-shared-olibpow.sounsgn_pow.o
下面編譯主程序,它將會(huì)鏈接到剛生成的動(dòng)態(tài)庫(kù)libpow.so。
[root@localhostlib]#gcc-opow_testpow_test.c-L.–lpow
在運(yùn)行可執(zhí)行程序之前,需要注冊(cè)動(dòng)態(tài)庫(kù)的路徑名。其方法有幾種:修改/etc/ld.so.conf文件,或者修改LD_LIBRARY_PATH環(huán)境變量,或者將庫(kù)文件直接復(fù)制到/lib或者/usr/lib目錄下(這兩個(gè)目錄為系統(tǒng)的默認(rèn)的庫(kù)路徑名)。
[root@localhostlib]#cplibpow.so/lib
[root@localhostlib]#./pow_test210
2^10=1024
動(dòng)態(tài)庫(kù)只有當(dāng)使用它的程序執(zhí)行時(shí)才被鏈接使用,而不是將需要的部分直接編譯入可執(zhí)行文件中,并且一個(gè)動(dòng)態(tài)庫(kù)可以被多個(gè)程序使用故可稱(chēng)為共享庫(kù),而靜態(tài)庫(kù)將會(huì)整合到程序中,因此在程序執(zhí)行時(shí)不用加載靜態(tài)庫(kù)。從而可知,鏈接到靜態(tài)庫(kù)會(huì)使用戶的程序臃腫,并且難以升級(jí),但是可能會(huì)比較容易部署。而鏈接到動(dòng)態(tài)庫(kù)會(huì)使用戶的程序輕便,并且易于升級(jí),但是會(huì)難以部署。
(3)告警和出錯(cuò)選項(xiàng)。
gcc的告警和出錯(cuò)選項(xiàng)如表3.9所示。
表3.9 gcc警告和出錯(cuò)選項(xiàng)選項(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í)終止編譯過(guò)程
下面結(jié)合實(shí)例對(duì)這幾個(gè)告警和出錯(cuò)選項(xiàng)進(jìn)行簡(jiǎn)單的講解。
有以下程序段:
#include<stdio.h>
voidmain()
{
longlongtmp=1;
printf("Thisisabadcode!\n");
return0;
}
這是一個(gè)很糟糕的程序,讀者可以考慮一下有哪些問(wèn)題。
n “-ansi”
該選項(xiàng)強(qiáng)制gcc生成標(biāo)準(zhǔn)語(yǔ)法所要求的告警信息,盡管這還并不能保證所有沒(méi)有警告的程序都是符合ANSIC標(biāo)準(zhǔn)的。運(yùn)行結(jié)果如下所示:
[root@localhostgcc]#gcc–ansiwarning.c–owarning
warning.c:在函數(shù)“main”中:
warning.c:7警告:在無(wú)返回值的函數(shù)中,“return”帶返回值
warning.c:4警告:“main”的返回類(lèi)型不是“int”
可以看出,該選項(xiàng)并沒(méi)有發(fā)現(xiàn)“longlong”這個(gè)無(wú)效數(shù)據(jù)類(lèi)型的錯(cuò)誤。
n “-pedantic”
打印ANSIC標(biāo)準(zhǔn)所列出的全部警告信息,同樣也保證所有沒(méi)有警告的程序都是符合ANSIC標(biāo)準(zhǔn)的。其運(yùn)行結(jié)果如下所示:
[root@localhostgcc]#gcc–pedanticwarning.c–owarning
warning.c:在函數(shù)“main”中:
warning.c:5警告:ISOC90不支持“longlong”
warning.c:7警告:在無(wú)返回值的函數(shù)中,“return”帶返回值
warning.c:4警告:“main”的返回類(lèi)型不是“int”
可以看出,使用該選項(xiàng)查出了“longlong”這個(gè)無(wú)效數(shù)據(jù)類(lèi)型的錯(cuò)誤。
n “-Wall”
打印gcc能夠提供的所有有用的報(bào)警信息。該選項(xiàng)的運(yùn)行結(jié)果如下所示:
[root@localhostgcc]#gcc–Wallwarning.c–owarning
warning.c:4警告:“main”的返回類(lèi)型不是“int”
warning.c:在函數(shù)“main”中:
warning.c:7警告:在無(wú)返回值的函數(shù)中,“return”帶返回值
warning.c:5警告:未使用的變量“tmp”
使用“-Wall”選項(xiàng)找出了未使用的變量tmp,但它并沒(méi)有找出無(wú)效數(shù)據(jù)類(lèi)型的錯(cuò)誤。
另外,gcc還可以利用選項(xiàng)對(duì)單獨(dú)的常見(jiàn)錯(cuò)誤分別指定警告。
(4)優(yōu)化選項(xiàng)。
gcc可以對(duì)代碼進(jìn)行優(yōu)化,它通過(guò)編譯選項(xiàng)“-On”來(lái)控制優(yōu)化代碼的生成,其中n是一個(gè)代表優(yōu)化級(jí)別的整數(shù)。對(duì)于不同版本的gcc來(lái)講,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)展開(kāi)和其他一些與處理器特性相關(guān)的優(yōu)化工作。
雖然優(yōu)化選項(xiàng)可以加速代碼的運(yùn)行速度,但對(duì)于調(diào)試而言將是一個(gè)很大的挑戰(zhàn)。因?yàn)榇a在經(jīng)過(guò)優(yōu)化之后,原先在源程序中聲明和使用的變量很可能不再使用,控制流也可能會(huì)突然跳轉(zhuǎn)到意外的地方,循環(huán)語(yǔ)句也有可能因?yàn)檠h(huán)展開(kāi)而變得到處都有,所有這些對(duì)調(diào)試來(lái)講都將是一場(chǎng)噩夢(mèng)。所以筆者建議在調(diào)試的時(shí)候最好不使用任何優(yōu)化選項(xiàng),只有當(dāng)程序在最終發(fā)行的時(shí)候才考慮對(duì)其進(jìn)行優(yōu)化。
(5)體系結(jié)構(gòu)相關(guān)選項(xiàng)。
gcc的體系結(jié)構(gòu)相關(guān)選項(xiàng)如表3.10所示。
表3.10 gcc體系結(jié)構(gòu)相關(guān)選項(xiàng)列表
選項(xiàng)
含義
-mcpu=type
針對(duì)不同的CPU使用相應(yīng)的CPU指令。可選擇的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)庫(kù)調(diào)用的目標(biāo)代碼
-mshort
把int類(lèi)型作為16位處理,相當(dāng)于shortint
-mrtd
強(qiáng)行將函數(shù)參數(shù)個(gè)數(shù)固定的函數(shù)用retNUM返回,節(jié)省調(diào)用函數(shù)的一條指令
這些體系結(jié)構(gòu)相關(guān)選項(xiàng)在嵌入式的設(shè)計(jì)中會(huì)有較多的應(yīng)用,讀者需根據(jù)不同體系結(jié)構(gòu)將對(duì)應(yīng)的選項(xiàng)進(jìn)行組合處理。在本書(shū)后面涉及具體實(shí)例時(shí)將會(huì)有針對(duì)性的講解。