国产精品久久久aaaa,日日干夜夜操天天插,亚洲乱熟女香蕉一区二区三区少妇,99精品国产高清一区二区三区,国产成人精品一区二区色戒,久久久国产精品成人免费,亚洲精品毛片久久久久,99久久婷婷国产综合精品电影,国产一区二区三区任你鲁

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

預處理相關知識點總結

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

掃碼添加小助手

加入工程師交流群

處理器

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

預定義符號

1.預處理器定義了一些符號,他們的值或者是字符串常量,或者是十進制數字常量,FILE的含義是進行編譯的源文件名。

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

#define

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

#definename(parameter-list)stuff

其中,parameter-list(參數列表)是一個由逗號分隔的值的列表,每個值都與宏定義中的一個參數相對應,整個列表用一對括號包圍。當參數出現在程序中時,與每個參數對應的實際值都將被替換到 stuff 中。這里由一個宏。它接受一個參數:

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

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

((5)*(5))

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

#define 替換

在程序中擴展#define定義符號和宏時,需要涉及幾個步驟。

在調用宏時,首先對參數進行檢查,看看是否包含了任何由#define定義的符號。如果是,他們首先被替換。

替換文本隨后被插入到程序中原來文本的位置。對于宏,參數名被他們的值所替代。

最后,再次對結果文本進行掃描,看看它是否包含了任何由#define定義的符號。如果是,就重復上述處理過程。

這樣,宏參數和#define定義可以包含其他#define定義的符號。但是,宏不可以出現遞歸。

#argument 替換符號

當預處理器搜索#define定義的符號時,字符串常量的內容并不進行檢查。#argument 這種結構被預處理器翻譯為 "argument",可以把一個宏參數轉化為字符串。如果想把宏參數插入到字符串常量中,可以使用下面的技巧:

技巧一

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

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

輸出結果:

Thevalueis9

技巧二

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

輸出結果:

thevalueofx+3is9

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

技巧三

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

輸出結果:

helloSummerGift

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

##連接符號

##結構把位于它兩邊的符號連接成一個符號。作為用途之一,它允許宏定義從分離的文本片段創建標識符。下面的這個例子使用這種連接把一個值添加到幾個變量之一:

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

最后一條語句把值25加到變量 sum5。注意這種連接必須產生一個合法的標識符。否則其結果就是未定義的。

宏與函數

用宏來完成比較簡單的計算,比如比較兩個表達式的大小的好處是,如果使用函數來實現,用于調用和從函數返回的代碼很可能比實際執行這個小型計算任務的代碼更大,所以使用宏比使用函數在程序的規模和速度方面都更勝一籌。#define MAX(A, B) ((A)>(B) ? (A):(B))

更為重要的是,函數的參數必須聲明為一種特定的類型,所以它只能在類型合適的表達式上使用。反之,上面這個宏可以用于整形、長整形、單浮點型、雙浮點數以及其他任何可以用 > 操作符比較值大小的類型。換句話說,宏是與類型無關的。

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

還有一些任務根本無法用函數實現。比如下面的宏定義,這個宏的第二個參數是一種類型,它無法作為函數參數進行傳遞。

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

實際轉換過程如下:

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

帶副作用的宏參數

當宏參數在宏定義中出現的次數超過一次時,如果這個參數具有副作用,那么當你使用這個宏時就出現危險導致不可預料的結果。副作用就是在表達式求值時出現的永久性結果,例如:

x+1

這個表達式可以重復執行幾百次,他每次獲得的值結果都是一樣的。這個表達式不具有副作用。但是

x++

就具有副作用:它增加 x 的值。當這個表達式下一次執行時,它將產生一個不同的結果。MAX宏可以證明具有副作用的參數引起的問題。

#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);
這個宏的結果是 x = 6, y = 10, z = 9。
檢查替換后的結果:z =(x++)>(y++) ? (x++):(y++);

那個較小的值只增值了一次,而那個較大的值卻增值了兩次,第一次是在比較的時候,第二次是在執行 ?后面的表達式的時候。

命名約定

為宏采納一種命名約定是很重要的,用來區分一個名稱是一個函數還是一個宏,避免發生混淆。

#undef

這條預處理指令用于移除一個宏定義。

#undefname

如果一個現存的名字需要被重新定義,那么他的舊定義首先必須用#undef移除。如果一個宏不想讓后面的程序用了,那么就將其 undef ,如果后面使用了這個宏就會報錯。

命令行定義

許多編譯器提供了一種能力,允許在命令行中定義符號,用于啟動編譯過程。當我們根據同一個源文件編譯一個程序的不同版本時,這個特性是很有用的。例如有如下數組:

intarray[ARRAY_SIZE];

那么在UNIX系統中,編譯這個程序的命令行很可能是下面的樣子:

cc-DARRY_SIZE=100prog.c

條件編譯

常見的條件編譯:

#ifconstant-expression
statments
#endif

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

是否被定義

測試一個符號是否被定義也是可能的。在條件編譯中完成這個任務往往更方便,因為程序如果并不需要控制編譯的符號所控制的特性,他就不需要被定義。這個測試可以用下面的方式來進行:

#ifdefined(symbol)
#ifdefsymbol

#if!defined(symbol)
#ifndefsymbol

每對定義的兩條語句是等價的,但#if形式功能更強。因為常量表達式可能包含額外的條件,如下面所示:

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

嵌套指令

上面提到的這些指令可以嵌套于另一個指令內部。

#ifxxx
statments
#elifxxx
statments
#endif

文件包含

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

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

函數庫文件包含

函數庫頭文件包含使用下面的語法:

#include

這種情況的包含會在系統目錄里尋找函數庫頭文件。也可以使用編譯器選項添加自己的文件函數庫。

本地文件包含

本地頭文件包含使用下面的語法:

#include"filename"

這種情況的包含會先在當前目錄進行查找,如果未找到再像查找函數庫頭文件一樣在標準位置查找本地頭文件。嵌套文件包含 使用條件編譯來避免重復包含頭文件出現的錯誤:

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

其他指令

#error指令允許生成錯誤信息
#errortextoferrormessage

使用方法:

#errornooptionselsected
#line修改下一行輸入的行號
#linenumber"string"

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

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

#progma指令是另一種機制,用于支持因編譯器而異的機制。它的語法也是因編譯器而異。有些環境可能提供一些#progma指令,允許一些編譯選項或者其他任何任何方式無法實現的一些處理方式。例如有些編譯器使用progma指令在編譯過程中打開或者關閉清單顯示,或者把會變代碼插入到 C 程序中。從本質上說,#progma是不可移植的。預處理器將忽略他們不認識的#progma指令,兩個不同的編譯器可能以兩種不同的方式解釋同一條#progma指令。

#(null directive) 無效指令

無效指令就是一個#開頭,但后面不跟任何內容的一行。這類指令只是被預處理器簡單地刪除。下面的例子中無效指令通過把#include與周圍的代碼分隔開來,凸顯它的存在。

#
#include
#

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

總結

警告的總結

不要在一個宏定義的末尾加上分號,使其成為一條完整的語句。

在宏定義中使用參數,但忘了在他們周圍加上括號。

忘了在整個宏定義的兩邊加上括號。

編程提示的總結

避免用 #define 指令定義可以用函數實現的很長序列的代碼。

在那些對表達式求值的宏中,每個宏參數出現的地方都應該加上括號,并且在整個宏定義的兩邊也加上括號。

避免使用 #define 宏創建一種新的語言。

采用采用命名約定,使程序員很容易看出某個標識符是否為 #define 宏。

只要合適就應該使用文件包含,不必擔心它的額外開銷。

頭文件只應該包含一組函數和(或)數據的聲明。

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

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

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 指令
    +關注

    關注

    1

    文章

    623

    瀏覽量

    37529
  • 字符串
    +關注

    關注

    1

    文章

    596

    瀏覽量

    23165
  • 編譯
    +關注

    關注

    0

    文章

    694

    瀏覽量

    35158
  • C程序
    +關注

    關注

    4

    文章

    255

    瀏覽量

    37622
  • 預處理器
    +關注

    關注

    0

    文章

    13

    瀏覽量

    2372

原文標題:預處理相關知識點總結

文章出處:【微信號:嵌入式應用研究院,微信公眾號:嵌入式應用研究院】歡迎添加關注!文章轉載請注明出處。

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

掃碼添加小助手

加入工程師交流群

    評論

    相關推薦
    熱點推薦

    嵌入式C語言知識點總結

    怎么才能做好嵌入式開發?學好C語言吧!今天就來推薦一篇大佬寫的嵌入式C語言知識點總結
    發表于 09-27 09:53 ?1621次閱讀

    關于工業相機相關知識點總結的太棒了

    關于工業相機相關知識點總結的太棒了
    發表于 09-29 07:56

    C語言程序小知識點總結

    C語言總結(stm32嵌入式開發)文章目錄C語言總結(stm32嵌入式開發)c程序小知識點總結1.靜態變量static與外部變量extern的使用2.函數封裝后返回值的方法3.軟件寄存
    發表于 11-05 07:45

    高一數學知識點總結

    高一數學知識點總結高一數學知識點總結高一數學知識點總結
    發表于 02-23 15:27 ?0次下載

    高二數學知識點總結

    高二數學知識點總結高二數學知識點總結高二數學知識點總結
    發表于 02-23 15:27 ?0次下載

    復習圖像處理知識點

    中南大學數字圖像預處理復習知識點,里面包含里所有的考點,可以參考。很全面。
    發表于 05-10 15:48 ?0次下載

    C語言學習入門知識點/干貨

    C語言知識點總結
    的頭像 發表于 07-18 17:54 ?6826次閱讀
    C語言學習入門<b class='flag-5'>知識點</b>/干貨

    Python的知識點總結詳細說明

    本文檔的主要內容詳細介紹的是Python的知識點總結詳細說明。
    發表于 09-29 17:13 ?16次下載
    Python的<b class='flag-5'>知識點</b><b class='flag-5'>總結</b>詳細說明

    嵌入式知識點總結

    嵌入式知識點總結(arm嵌入式開發led過程)-嵌入式知識點總結? ? ? ? ? ? ? ? ? ??
    發表于 07-30 14:20 ?23次下載
    嵌入式<b class='flag-5'>知識點</b><b class='flag-5'>總結</b>

    開關電源模塊知識點總結

    開關電源模塊知識點總結(現代電源技術基礎pdf)-該文檔為開關電源模塊知識點總結文檔,是一份不錯的參考資料,感興趣的可以下載看看,,,,,,,,,,,,,,,,,
    發表于 09-22 13:42 ?29次下載
    開關電源模塊<b class='flag-5'>知識點</b><b class='flag-5'>總結</b>

    數字信號處理知識點總結

    數字信號處理知識點總結
    發表于 08-15 15:16 ?0次下載

    C語言最重要的知識點

    C語言知識點總結.doc
    發表于 02-16 16:37 ?9次下載

    數字電路知識點總結

    本文整理了數字電路課程中的相關基本的知識點和較為重要的知識點,用于求職的數電部分的知識準備,差缺補漏。
    的頭像 發表于 05-30 15:07 ?6694次閱讀
    數字電路<b class='flag-5'>知識點</b><b class='flag-5'>總結</b>

    電阻的相關知識點

    電阻,一個最容易又是最基礎的電子元器件,看似簡單,然而實際情況根據芯片哥對多位經驗豐富的研發工程師的拜訪溝通得知并非如此;芯片哥如果讓開發工程師做出一個系統性的歸納總結,把電阻相關的所有內容知識點
    的頭像 發表于 09-13 10:19 ?3485次閱讀
    電阻的<b class='flag-5'>相關</b><b class='flag-5'>知識點</b>

    模擬電子技術知識點問題總結概覽

    給大家分享模擬電子技術知識點問題總結
    的頭像 發表于 05-08 15:16 ?2268次閱讀
    模擬電子技術<b class='flag-5'>知識點</b>問題<b class='flag-5'>總結</b>概覽