一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

預(yù)處理相關(guān)知識(shí)點(diǎn)總結(jié)

嵌入式應(yīng)用研究院 ? 來(lái)源:C語(yǔ)言編程筆記 ? 2023-05-31 09:52 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

預(yù)處理器

編譯一個(gè) C 程序設(shè)計(jì)很多步驟。其中第 1 個(gè)步驟被稱為預(yù)處理階段。C 預(yù)處理器在源代碼編譯之前對(duì)其進(jìn)行一些文本性質(zhì)的操作。他的主要任務(wù)包括刪除注釋、插入被 #include 指令包含的文件的內(nèi)容、定義、和替換由 #define 指令定義的符號(hào)以及確定代碼的部分內(nèi)容是否應(yīng)該根據(jù)一些條件編譯指令進(jìn)行編譯。

預(yù)定義符號(hào)

1.預(yù)處理器定義了一些符號(hào),他們的值或者是字符串常量,或者是十進(jìn)制數(shù)字常量,F(xiàn)ILE的含義是進(jìn)行編譯的源文件名。

35a0f28c-ff52-11ed-90ce-dac502259ad0.png

#define

#define 機(jī)制包括了一個(gè)規(guī)定,允許把參數(shù)替換到文本中,這種實(shí)現(xiàn)通常稱為宏(macro)或定義宏(defined macro)。下面是宏的聲明方式:

#definename(parameter-list)stuff

其中,parameter-list(參數(shù)列表)是一個(gè)由逗號(hào)分隔的值的列表,每個(gè)值都與宏定義中的一個(gè)參數(shù)相對(duì)應(yīng),整個(gè)列表用一對(duì)括號(hào)包圍。當(dāng)參數(shù)出現(xiàn)在程序中時(shí),與每個(gè)參數(shù)對(duì)應(yīng)的實(shí)際值都將被替換到 stuff 中。這里由一個(gè)宏。它接受一個(gè)參數(shù):

#defineSQUARE(x)((x)*(x))

如果在上述聲明之后把 SQUARE(5)置于程序中,預(yù)處理器就會(huì)用下面的這個(gè)表達(dá)式替換上面的表達(dá)式:

((5)*(5))

這里添加括號(hào)的原因是,為了避免在使用宏時(shí),由于參數(shù)中的操作符或鄰近的操作符之間不可預(yù)料的相互作用。

#define 替換

在程序中擴(kuò)展#define定義符號(hào)和宏時(shí),需要涉及幾個(gè)步驟。

在調(diào)用宏時(shí),首先對(duì)參數(shù)進(jìn)行檢查,看看是否包含了任何由#define定義的符號(hào)。如果是,他們首先被替換。

替換文本隨后被插入到程序中原來(lái)文本的位置。對(duì)于宏,參數(shù)名被他們的值所替代。

最后,再次對(duì)結(jié)果文本進(jìn)行掃描,看看它是否包含了任何由#define定義的符號(hào)。如果是,就重復(fù)上述處理過(guò)程。

這樣,宏參數(shù)和#define定義可以包含其他#define定義的符號(hào)。但是,宏不可以出現(xiàn)遞歸。

#argument 替換符號(hào)

當(dāng)預(yù)處理器搜索#define定義的符號(hào)時(shí),字符串常量的內(nèi)容并不進(jìn)行檢查。#argument 這種結(jié)構(gòu)被預(yù)處理器翻譯為 "argument",可以把一個(gè)宏參數(shù)轉(zhuǎn)化為字符串。如果想把宏參數(shù)插入到字符串常量中,可以使用下面的技巧:

技巧一

首先,臨近字符串自動(dòng)連接的特性使我們很容易把一個(gè)字符串分成幾段,每段實(shí)際上都是一個(gè)宏參數(shù)。例子如下:

#definePRINT(FORMAT,VALUE)
printf("Thevalueis"#FORMAT"",VALUE)
...
intx=6;
PRINT_FOR(%d,x+3);

輸出結(jié)果:

Thevalueis9

技巧二

#definePRINT_FOR(FORMAT,VALUE)
printf("thevalueof
"#VALUE"is"#FORMAT"
",VALUE)
...
PRINT_FOR(%d,x+3);

輸出結(jié)果:

thevalueofx+3is9

書上的技巧一和技巧二并不能通過(guò)編譯,我經(jīng)過(guò)修改的上面的兩個(gè)例子,我感覺(jué)是用了同一個(gè)技巧就是將字符串中的 "#VALUE" 替換成傳入的字符,如技巧二中介紹的將 #VALUE替換成了字符串中的 x+3,將 #FORMAT 替換成 %d,最后一個(gè) VALUE 作為實(shí)際的參數(shù)只是進(jìn)行了簡(jiǎn)單的文本替換,不涉及字符串修改。

技巧三

#definePRINT(VALUE)printf(#VALUE)
...
PRINT(helloSummerGift);

輸出結(jié)果:

helloSummerGift

技巧三展示了基本的 #argument功能,即將 #VALUE替換成 "hello SummerGift",也就是將 hello SummerGift 簡(jiǎn)單替換成了 "hello SummerGift"。

##連接符號(hào)

##結(jié)構(gòu)把位于它兩邊的符號(hào)連接成一個(gè)符號(hào)。作為用途之一,它允許宏定義從分離的文本片段創(chuàng)建標(biāo)識(shí)符。下面的這個(gè)例子使用這種連接把一個(gè)值添加到幾個(gè)變量之一:

#defineADD_TO_SUM(sum_number,value)
sum##sum_number+=value
...
ADD_TO_SUM(5,25);

最后一條語(yǔ)句把值25加到變量 sum5。注意這種連接必須產(chǎn)生一個(gè)合法的標(biāo)識(shí)符。否則其結(jié)果就是未定義的。

宏與函數(shù)

用宏來(lái)完成比較簡(jiǎn)單的計(jì)算,比如比較兩個(gè)表達(dá)式的大小的好處是,如果使用函數(shù)來(lái)實(shí)現(xiàn),用于調(diào)用和從函數(shù)返回的代碼很可能比實(shí)際執(zhí)行這個(gè)小型計(jì)算任務(wù)的代碼更大,所以使用宏比使用函數(shù)在程序的規(guī)模和速度方面都更勝一籌。#define MAX(A, B) ((A)>(B) ? (A):(B))

更為重要的是,函數(shù)的參數(shù)必須聲明為一種特定的類型,所以它只能在類型合適的表達(dá)式上使用。反之,上面這個(gè)宏可以用于整形、長(zhǎng)整形、單浮點(diǎn)型、雙浮點(diǎn)數(shù)以及其他任何可以用 > 操作符比較值大小的類型。換句話說(shuō),宏是與類型無(wú)關(guān)的。

與函數(shù)相比,使用宏的不利之處在于每次使用宏時(shí),一份宏定義代碼的拷貝都將插入到程序中。除非宏非常短,否則使用宏可能會(huì)大幅度增加程序的長(zhǎng)度。

還有一些任務(wù)根本無(wú)法用函數(shù)實(shí)現(xiàn)。比如下面的宏定義,這個(gè)宏的第二個(gè)參數(shù)是一種類型,它無(wú)法作為函數(shù)參數(shù)進(jìn)行傳遞。

#defineMALLOC(n,type)
((type*)malloc((n)*sizeof(type)))

實(shí)際轉(zhuǎn)換過(guò)程如下:

轉(zhuǎn)換前:pi = MALLOC(25, int);
轉(zhuǎn)換后:pi =((int *)malloc((25)* sizeof( int )))

帶副作用的宏參數(shù)

當(dāng)宏參數(shù)在宏定義中出現(xiàn)的次數(shù)超過(guò)一次時(shí),如果這個(gè)參數(shù)具有副作用,那么當(dāng)你使用這個(gè)宏時(shí)就出現(xiàn)危險(xiǎn)導(dǎo)致不可預(yù)料的結(jié)果。副作用就是在表達(dá)式求值時(shí)出現(xiàn)的永久性結(jié)果,例如:

x+1

這個(gè)表達(dá)式可以重復(fù)執(zhí)行幾百次,他每次獲得的值結(jié)果都是一樣的。這個(gè)表達(dá)式不具有副作用。但是

x++

就具有副作用:它增加 x 的值。當(dāng)這個(gè)表達(dá)式下一次執(zhí)行時(shí),它將產(chǎn)生一個(gè)不同的結(jié)果。MAX宏可以證明具有副作用的參數(shù)引起的問(wèn)題。

#defineMAX(A,B)((A)>(B)?(A):(B))
...
x=5;
y=8;
z=MAX(x,y);
printf("x=%d,y=%d,z=%d",x,y,z);
這個(gè)宏的結(jié)果是 x = 6, y = 10, z = 9。
檢查替換后的結(jié)果:z =(x++)>(y++) ? (x++):(y++);

那個(gè)較小的值只增值了一次,而那個(gè)較大的值卻增值了兩次,第一次是在比較的時(shí)候,第二次是在執(zhí)行 ?后面的表達(dá)式的時(shí)候。

命名約定

為宏采納一種命名約定是很重要的,用來(lái)區(qū)分一個(gè)名稱是一個(gè)函數(shù)還是一個(gè)宏,避免發(fā)生混淆。

#undef

這條預(yù)處理指令用于移除一個(gè)宏定義。

#undefname

如果一個(gè)現(xiàn)存的名字需要被重新定義,那么他的舊定義首先必須用#undef移除。如果一個(gè)宏不想讓后面的程序用了,那么就將其 undef ,如果后面使用了這個(gè)宏就會(huì)報(bào)錯(cuò)。

命令行定義

許多編譯器提供了一種能力,允許在命令行中定義符號(hào),用于啟動(dòng)編譯過(guò)程。當(dāng)我們根據(jù)同一個(gè)源文件編譯一個(gè)程序的不同版本時(shí),這個(gè)特性是很有用的。例如有如下數(shù)組:

intarray[ARRAY_SIZE];

那么在UNIX系統(tǒng)中,編譯這個(gè)程序的命令行很可能是下面的樣子:

cc-DARRY_SIZE=100prog.c

條件編譯

常見(jiàn)的條件編譯:

#ifconstant-expression
statments
#endif

其中,constant-expression(常量表達(dá)式)由預(yù)處理器進(jìn)行求值,如果其值為真,則statements部分就被正常編譯,否則預(yù)處理器就安靜地刪除他們。

是否被定義

測(cè)試一個(gè)符號(hào)是否被定義也是可能的。在條件編譯中完成這個(gè)任務(wù)往往更方便,因?yàn)槌绦蛉绻⒉恍枰刂凭幾g的符號(hào)所控制的特性,他就不需要被定義。這個(gè)測(cè)試可以用下面的方式來(lái)進(jìn)行:

#ifdefined(symbol)
#ifdefsymbol

#if!defined(symbol)
#ifndefsymbol

每對(duì)定義的兩條語(yǔ)句是等價(jià)的,但#if形式功能更強(qiáng)。因?yàn)槌A勘磉_(dá)式可能包含額外的條件,如下面所示:

#ifx>0||defined(ABD)&&defined(BCD)

嵌套指令

上面提到的這些指令可以嵌套于另一個(gè)指令內(nèi)部。

#ifxxx
statments
#elifxxx
statments
#endif

文件包含

使用#include指令的替換執(zhí)行方式很簡(jiǎn)單,預(yù)處理刪除這條指令,并用包含文件的內(nèi)容取而代之。這樣一個(gè)頭文件如果被包含到10個(gè)源文件中,它實(shí)際被編譯了10次。

編譯器支持兩種不同類型的 #include文件包含:函數(shù)庫(kù)文件和本地文件。實(shí)際上,他們之間的區(qū)別很小。

函數(shù)庫(kù)文件包含

函數(shù)庫(kù)頭文件包含使用下面的語(yǔ)法:

#include

這種情況的包含會(huì)在系統(tǒng)目錄里尋找函數(shù)庫(kù)頭文件。也可以使用編譯器選項(xiàng)添加自己的文件函數(shù)庫(kù)。

本地文件包含

本地頭文件包含使用下面的語(yǔ)法:

#include"filename"

這種情況的包含會(huì)先在當(dāng)前目錄進(jìn)行查找,如果未找到再像查找函數(shù)庫(kù)頭文件一樣在標(biāo)準(zhǔn)位置查找本地頭文件。嵌套文件包含 使用條件編譯來(lái)避免重復(fù)包含頭文件出現(xiàn)的錯(cuò)誤:

#ifndef__HEADERNAME__H
#define__HEADERNAME__H1
/*
**Allthestuffthatyouwangintheheaderfile
*/
#endif

其他指令

#error指令允許生成錯(cuò)誤信息
#errortextoferrormessage

使用方法:

#errornooptionselsected
#line修改下一行輸入的行號(hào)
#linenumber"string"

它通知預(yù)處理器 number 使下一行輸入的行號(hào)。如果給出了可選部分 string ,預(yù)處理器就把他當(dāng)作當(dāng)前文件的名字。值得注意的是,這條指令修改__LINE__符號(hào)的值,如果加上可選部分,他還將修改__FILE__符號(hào)的值。

#progma用于支持因編譯器而異的特性

#progma指令是另一種機(jī)制,用于支持因編譯器而異的機(jī)制。它的語(yǔ)法也是因編譯器而異。有些環(huán)境可能提供一些#progma指令,允許一些編譯選項(xiàng)或者其他任何任何方式無(wú)法實(shí)現(xiàn)的一些處理方式。例如有些編譯器使用progma指令在編譯過(guò)程中打開(kāi)或者關(guān)閉清單顯示,或者把會(huì)變代碼插入到 C 程序中。從本質(zhì)上說(shuō),#progma是不可移植的。預(yù)處理器將忽略他們不認(rèn)識(shí)的#progma指令,兩個(gè)不同的編譯器可能以兩種不同的方式解釋同一條#progma指令。

#(null directive) 無(wú)效指令

無(wú)效指令就是一個(gè)#開(kāi)頭,但后面不跟任何內(nèi)容的一行。這類指令只是被預(yù)處理器簡(jiǎn)單地刪除。下面的例子中無(wú)效指令通過(guò)把#include與周圍的代碼分隔開(kāi)來(lái),凸顯它的存在。

#
#include
#

插入空行也可以取得相同的效果。

總結(jié)

警告的總結(jié)

不要在一個(gè)宏定義的末尾加上分號(hào),使其成為一條完整的語(yǔ)句。

在宏定義中使用參數(shù),但忘了在他們周圍加上括號(hào)。

忘了在整個(gè)宏定義的兩邊加上括號(hào)。

編程提示的總結(jié)

避免用 #define 指令定義可以用函數(shù)實(shí)現(xiàn)的很長(zhǎng)序列的代碼。

在那些對(duì)表達(dá)式求值的宏中,每個(gè)宏參數(shù)出現(xiàn)的地方都應(yīng)該加上括號(hào),并且在整個(gè)宏定義的兩邊也加上括號(hào)。

避免使用 #define 宏創(chuàng)建一種新的語(yǔ)言。

采用采用命名約定,使程序員很容易看出某個(gè)標(biāo)識(shí)符是否為 #define 宏。

只要合適就應(yīng)該使用文件包含,不必?fù)?dān)心它的額外開(kāi)銷。

頭文件只應(yīng)該包含一組函數(shù)和(或)數(shù)據(jù)的聲明。

把不同集合的聲明分離到不同的頭文件中可以改善信息隱藏。

嵌套的 #include 文件是我們很難判斷源文件之間的依賴關(guān)系。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 指令
    +關(guān)注

    關(guān)注

    1

    文章

    616

    瀏覽量

    36490
  • 字符串
    +關(guān)注

    關(guān)注

    1

    文章

    590

    瀏覽量

    22306
  • 編譯
    +關(guān)注

    關(guān)注

    0

    文章

    679

    瀏覽量

    34022
  • C程序
    +關(guān)注

    關(guān)注

    4

    文章

    255

    瀏覽量

    36838
  • 預(yù)處理器
    +關(guān)注

    關(guān)注

    0

    文章

    13

    瀏覽量

    2315

原文標(biāo)題:預(yù)處理相關(guān)知識(shí)點(diǎn)總結(jié)

文章出處:【微信號(hào):嵌入式應(yīng)用研究院,微信公眾號(hào):嵌入式應(yīng)用研究院】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)

    怎么才能做好嵌入式開(kāi)發(fā)?學(xué)好C語(yǔ)言吧!今天就來(lái)推薦一篇大佬寫的嵌入式C語(yǔ)言知識(shí)點(diǎn)總結(jié)。
    發(fā)表于 09-27 09:53 ?1392次閱讀

    關(guān)于工業(yè)相機(jī)相關(guān)知識(shí)點(diǎn)總結(jié)的太棒了

    關(guān)于工業(yè)相機(jī)相關(guān)知識(shí)點(diǎn)總結(jié)的太棒了
    發(fā)表于 09-29 07:56

    C語(yǔ)言程序小知識(shí)點(diǎn)總結(jié)

    C語(yǔ)言總結(jié)(stm32嵌入式開(kāi)發(fā))文章目錄C語(yǔ)言總結(jié)(stm32嵌入式開(kāi)發(fā))c程序小知識(shí)點(diǎn)總結(jié)1.靜態(tài)變量static與外部變量extern的使用2.函數(shù)封裝后返回值的方法3.軟件寄存
    發(fā)表于 11-05 07:45

    高一數(shù)學(xué)知識(shí)點(diǎn)總結(jié)

    高一數(shù)學(xué)知識(shí)點(diǎn)總結(jié)高一數(shù)學(xué)知識(shí)點(diǎn)總結(jié)高一數(shù)學(xué)知識(shí)點(diǎn)總結(jié)
    發(fā)表于 02-23 15:27 ?0次下載

    高二數(shù)學(xué)知識(shí)點(diǎn)總結(jié)

    高二數(shù)學(xué)知識(shí)點(diǎn)總結(jié)高二數(shù)學(xué)知識(shí)點(diǎn)總結(jié)高二數(shù)學(xué)知識(shí)點(diǎn)總結(jié)
    發(fā)表于 02-23 15:27 ?0次下載

    復(fù)習(xí)圖像處理知識(shí)點(diǎn)

    中南大學(xué)數(shù)字圖像預(yù)處理復(fù)習(xí)知識(shí)點(diǎn),里面包含里所有的考點(diǎn),可以參考。很全面。
    發(fā)表于 05-10 15:48 ?0次下載

    C語(yǔ)言學(xué)習(xí)入門知識(shí)點(diǎn)/干貨

    C語(yǔ)言知識(shí)點(diǎn)總結(jié)
    的頭像 發(fā)表于 07-18 17:54 ?6322次閱讀
    C語(yǔ)言學(xué)習(xí)入門<b class='flag-5'>知識(shí)點(diǎn)</b>/干貨

    Python的知識(shí)點(diǎn)總結(jié)詳細(xì)說(shuō)明

    本文檔的主要內(nèi)容詳細(xì)介紹的是Python的知識(shí)點(diǎn)總結(jié)詳細(xì)說(shuō)明。
    發(fā)表于 09-29 17:13 ?14次下載
    Python的<b class='flag-5'>知識(shí)點(diǎn)</b><b class='flag-5'>總結(jié)</b>詳細(xì)說(shuō)明

    嵌入式知識(shí)點(diǎn)總結(jié)

    嵌入式知識(shí)點(diǎn)總結(jié)(arm嵌入式開(kāi)發(fā)led過(guò)程)-嵌入式知識(shí)點(diǎn)總結(jié)? ? ? ? ? ? ? ? ? ??
    發(fā)表于 07-30 14:20 ?23次下載
    嵌入式<b class='flag-5'>知識(shí)點(diǎn)</b><b class='flag-5'>總結(jié)</b>

    開(kāi)關(guān)電源模塊知識(shí)點(diǎn)總結(jié)

    開(kāi)關(guān)電源模塊知識(shí)點(diǎn)總結(jié)(現(xiàn)代電源技術(shù)基礎(chǔ)pdf)-該文檔為開(kāi)關(guān)電源模塊知識(shí)點(diǎn)總結(jié)文檔,是一份不錯(cuò)的參考資料,感興趣的可以下載看看,,,,,,,,,,,,,,,,,
    發(fā)表于 09-22 13:42 ?27次下載
    開(kāi)關(guān)電源模塊<b class='flag-5'>知識(shí)點(diǎn)</b><b class='flag-5'>總結(jié)</b>

    數(shù)字信號(hào)處理知識(shí)點(diǎn)總結(jié)

    數(shù)字信號(hào)處理知識(shí)點(diǎn)總結(jié)
    發(fā)表于 08-15 15:16 ?0次下載

    C語(yǔ)言最重要的知識(shí)點(diǎn)

    C語(yǔ)言知識(shí)點(diǎn)總結(jié).doc
    發(fā)表于 02-16 16:37 ?9次下載

    數(shù)字電路知識(shí)點(diǎn)總結(jié)

    本文整理了數(shù)字電路課程中的相關(guān)基本的知識(shí)點(diǎn)和較為重要的知識(shí)點(diǎn),用于求職的數(shù)電部分的知識(shí)準(zhǔn)備,差缺補(bǔ)漏。
    的頭像 發(fā)表于 05-30 15:07 ?5714次閱讀
    數(shù)字電路<b class='flag-5'>知識(shí)點(diǎn)</b><b class='flag-5'>總結(jié)</b>

    電阻的相關(guān)知識(shí)點(diǎn)

    電阻,一個(gè)最容易又是最基礎(chǔ)的電子元器件,看似簡(jiǎn)單,然而實(shí)際情況根據(jù)芯片哥對(duì)多位經(jīng)驗(yàn)豐富的研發(fā)工程師的拜訪溝通得知并非如此;芯片哥如果讓開(kāi)發(fā)工程師做出一個(gè)系統(tǒng)性的歸納總結(jié),把電阻相關(guān)的所有內(nèi)容知識(shí)點(diǎn)
    的頭像 發(fā)表于 09-13 10:19 ?2396次閱讀
    電阻的<b class='flag-5'>相關(guān)</b><b class='flag-5'>知識(shí)點(diǎn)</b>

    模擬電子技術(shù)知識(shí)點(diǎn)問(wèn)題總結(jié)概覽

    給大家分享模擬電子技術(shù)知識(shí)點(diǎn)問(wèn)題總結(jié)。
    的頭像 發(fā)表于 05-08 15:16 ?1574次閱讀
    模擬電子技術(shù)<b class='flag-5'>知識(shí)點(diǎn)</b>問(wèn)題<b class='flag-5'>總結(jié)</b>概覽