娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

GCC編譯器原理(三)------編譯原理三:編譯過(guò)程---預(yù)處理

發(fā)布者:平安幸福最新更新時(shí)間:2024-08-22 來(lái)源: cnblogs關(guān)鍵字:GCC編譯器  編譯過(guò)程  預(yù)處理 手機(jī)看文章 掃描二維碼
隨時(shí)隨地手機(jī)看文章
  • Gcc的編譯流程分為了四個(gè)步驟:

    • 預(yù)處理,生成預(yù)編譯文件(.文件):gcc –E hello.c –o hello.i

    • 編譯,生成匯編代碼(.s文件):gcc –S hello.i –o hello.s

    • 匯編,生成目標(biāo)文件(.o文件):gcc –c hello.s –o hello.o

    • 鏈接,生成可執(zhí)行文件:gcc hello.o –o hello

一、預(yù)處理

預(yù)編譯程序讀出源代碼,對(duì)其中內(nèi)嵌的指示字進(jìn)行響應(yīng),產(chǎn)生源代碼的修改版本,修改后的版本會(huì)被編譯程序讀入。

在 GNU 術(shù)語(yǔ)中,預(yù)處理程序叫做 CPP。而 GNU 的可執(zhí)行程序叫做 cpp。

簡(jiǎn)單來(lái)說(shuō),預(yù)處理就是將要包含(include)的文件插入原文件中、將宏定義展開(kāi)、根據(jù)條件編譯命令選擇要使用的代碼,最后將這些代碼輸出到一個(gè) '.i' 文件中等待進(jìn)一步處理。

預(yù)編譯過(guò)程主要處理那些源代碼文件中以 '#'開(kāi)始的預(yù)編譯指令。比如'#include'、'#define'等,主要處理規(guī)則如下:

  • 將所有的 '#define' 刪除,并且展開(kāi)所有的宏定義

  • 處理所有條件預(yù)編譯指令,比如'#if'、'#ifdef'、'#elif'、'#else'、'#endif'

  • 處理'#include'預(yù)編譯指令,將被包含的文件插入到該預(yù)編譯指令的位置。注意,這個(gè)過(guò)程是遞歸進(jìn)行的,也就是說(shuō)被包含的文件可能還包含其他文件

  • 刪除所有的注釋'//'和'/* */'

  • 添加行號(hào)和文件名標(biāo)識(shí),比如 #2 'hello.c' 2,以便于編譯時(shí)編譯器產(chǎn)生調(diào)試用的行號(hào)信息及用于編譯時(shí)產(chǎn)生編譯錯(cuò)誤或警告時(shí)能夠顯示行號(hào)

  • 保留所有的 #pragma 編譯器指令,因?yàn)榫幾g器需要使用它們

經(jīng)過(guò)預(yù)編譯后的 .i 文件不包含任何宏定義,因?yàn)樗械暮暌呀?jīng)被展開(kāi),并且包含的文件也已經(jīng)被插入到 .i 文件中。所以當(dāng)我們無(wú)法判斷宏定義是否正確或頭文件包含是否正確的時(shí)候,可以查看預(yù)編譯后的文件來(lái)確定問(wèn)題。

對(duì) hello.c 進(jìn)行預(yù)編譯:gcc -E hello.c -o hello .i

# 28 指的是文件 /usr/include/stdio.h 中的第 28 行,后面的是文件標(biāo)識(shí)

1.1 預(yù)處理指令

源代碼中的預(yù)處理指令叫做指示字(directive) ,從源代碼中可以輕易發(fā)現(xiàn),它們以井號(hào)(#)開(kāi)始,在每行都是第一個(gè)非空字符。而井號(hào)通常都在第一列,后面緊跟著指示字的關(guān)鍵字。

指示字

描述

#define

定義宏名字,預(yù)處理程序會(huì)把這個(gè)宏擴(kuò)展到使用該名字的位置

#elif

由#if 指示字提供一個(gè)用于計(jì)算的可選表達(dá)式

#else

如果#if、#ifdef 或#ifndef 為假,提供一個(gè)用于編譯的可選代碼集合

#error

產(chǎn)生出錯(cuò)消息,掛起預(yù)處理程序

#if

如果計(jì)算算術(shù)表達(dá)式的結(jié)果為非零值,就編譯指示字和它匹配的#endif 之間的代碼

#ifdef

如果已經(jīng)定義了指定的宏,就編譯指示字和它匹配的#endif 之間的代碼

#ifndef

如果沒(méi)有定義指定的宏,就編譯指示字和它匹配的#endif 之間的代碼

#include

查找指示字列表,直到找到指定的文件,然后將文件內(nèi)容插入,就好像在文本編輯器中插入一樣

#include_next

和#include 一樣,但該指示字從找到當(dāng)前文件的目錄之后的目錄開(kāi)始查找

#line

指出行號(hào)以及可能的文件名,報(bào)告給編譯程序,用于創(chuàng)建目標(biāo)文件中的調(diào)試信息

#pragma

提供額外信息的標(biāo)準(zhǔn)方法,可用來(lái)指出一個(gè)編譯程序或一個(gè)平臺(tái)

#undef

刪除前面用#define 指示字創(chuàng)建的定義

#warning

由預(yù)處理程序創(chuàng)建一個(gè)警告消息

##

連接操作符,可用于宏內(nèi)將兩個(gè)字符串連接成一個(gè)

1.1.1 #define

  • 通過(guò)處理傳遞給宏的參數(shù)名字,加上井號(hào)(#)就可將其'字符串化'

  • 可變的宏是具有可變數(shù)目參數(shù)的宏。這些參數(shù)由省略號(hào)代表,被保存在一個(gè)由逗號(hào)分隔的字符串中作為變量__VA_ARGS__,它會(huì)在宏的內(nèi)部進(jìn)行擴(kuò)展。例如,下面的宏接受任何數(shù)目的參數(shù):

  • 可變的宏可以包含命名的參數(shù)(只要隨后有參數(shù)的變量長(zhǎng)度列表) 。例如,下面的宏有兩個(gè)固定參數(shù),以及一個(gè)變量列表:

前面所有形式的可變宏至少有一個(gè)參數(shù)需要滿(mǎn)足參數(shù)變量列表的需求,因?yàn)開(kāi)_VA_ARGS__前面是一個(gè)逗號(hào),它用于宏內(nèi)部的 fprintf()函數(shù)調(diào)用。作為連接操作符的一個(gè)特例,可以要求在__VA_ARGS__為空時(shí),將它插入變量列表可以去掉逗號(hào),如下:

1.1.2 #error 和 #warning

#error 指示字會(huì)引起預(yù)處理程序報(bào)告致命錯(cuò)誤或中斷。它可用來(lái)捕獲嘗試按照某種不可能工作的形式進(jìn)行編譯的條件。例如,下面的例子只有在定義了__unix__的情況下才能成功編譯:

#warning 指示字和#error 指示字的工作原理一樣

1.1.3 #include_next

#include_next 指示字只用于某些特殊情況。它用在頭文件內(nèi)部來(lái)包含其他頭文件,會(huì)令新頭文件的查找由找到當(dāng)前頭文件的目錄之后的目錄開(kāi)始

1.1.4 #line

調(diào)試器需要將文件名和行號(hào)與數(shù)據(jù)項(xiàng)和可執(zhí)行代碼關(guān)聯(lián)起來(lái),因此預(yù)處理程序會(huì)將這類(lèi)信息插入編譯程序的輸出結(jié)果。有必要按這種方式跟蹤原始名字和行號(hào),因?yàn)轭A(yù)處理程序會(huì)組合一些文件。編譯程序在編譯插入目標(biāo)代碼中的表時(shí),會(huì)使用這些數(shù)字。

通常,允許預(yù)處理程序通過(guò)計(jì)算來(lái)確定行號(hào),這正是需要的,但也有可能用其他一些處理來(lái)去掉這些行號(hào)。例如,實(shí)現(xiàn) SQL 語(yǔ)句的通常方法就是將它們寫(xiě)成宏,然后用特殊的處理器將這些宏擴(kuò)展成具體的 SQL 函數(shù)調(diào)用。這些擴(kuò)展可在很多行中運(yùn)行,這樣計(jì)算行號(hào)就很困難。SQL 處理會(huì)通過(guò)在輸出中插入#line 指示字進(jìn)行更正,這樣預(yù)處理程序就會(huì)跟蹤原始源代碼的行號(hào)。

  • 可用于#line 指示字的特征和規(guī)則的列表:

    • 為#line 指示字指定一個(gè)數(shù)字,會(huì)令預(yù)處理程序?qū)?dāng)前行號(hào)替換為指定行號(hào);指示字設(shè)置當(dāng)前行號(hào)為 137:#line 137

    • 為#line 指示字指定行號(hào)和文件名,會(huì)令預(yù)處理程序改變行號(hào)以及當(dāng)前文件的名字。指示字會(huì)設(shè)置當(dāng)前位置為文件 muggles.h 的第一行:#line 1 'muggles.h'

    • #line 指示字修改預(yù)定義宏__LINE__ 和 __FILE__的內(nèi)容。

    • #line 指示字對(duì)由#include 指示字查找到的文件名或目錄沒(méi)有影響。

1.1.5 #pragma 和_Pragma

指示字#pragma 提供一種標(biāo)準(zhǔn)方法用來(lái)指定特定于編譯程序的信息。根據(jù)標(biāo)準(zhǔn),編譯程序可以附帶#pragma 指示字希望的任何意義。

所有 GCC pragma 都定義了兩個(gè)詞——第一個(gè)為 GCC,第二個(gè)為指定 pragma 的名字。

  • #pragma GCC dependency

    • dependency pragma 測(cè)試當(dāng)前文件的時(shí)間戳,對(duì)比其他文件的時(shí)間戳。如果其他文件更新,就會(huì)發(fā)出警告消息。測(cè)試文件 lexgen.tbl 的時(shí)間戳:

    • #pragma GCC dependency 'lexgen.tbl'

    • 如果 lexgen.tbl 比當(dāng)前文件新,預(yù)處理程序就會(huì)產(chǎn)生如下消息:

    • warning: current file is older than 'lexgen.tbl'

    • 可在 pragma 指示字中加入其他文本,它會(huì)作為警告消息的一部分,如下例所示:

    • #pragma GCC dependency 'lexgen.tbl' Header lex.h needs to be updated

    • 它會(huì)創(chuàng)建下面的警告消息:

    • show.c:26: warning: current file is older than 'lexgen.tbl'

    • show.c:26: warning: Header lex.h needs to be updated

  • #pragma GCC poison

    • poison pragma 在每次使用指定名字的時(shí)候都會(huì)發(fā)出消息。例如,可用它確保從未調(diào)用指定函數(shù)。

    • 下面的 pragma 在調(diào)用 memcpy 復(fù)本函數(shù)時(shí)就會(huì)發(fā)出警告消息:

    • #pragma GCC poison memcpy memmove

    • memcpy(target,source,size);

    • 預(yù)處理程序會(huì)為該代碼產(chǎn)生如下警告消息:

    • show.c:38:9: attempt to use poisoned 'memcpy

  • #pragma GCC system_header

    • 由 system_header pragma 打頭并隨后繼續(xù)到文件尾的代碼被看作是系統(tǒng)頭文件的一部分。編譯系統(tǒng)頭文件代碼有一些不同,因?yàn)檫\(yùn)行時(shí)庫(kù)不能被寫(xiě),因此它們是嚴(yán)格的純 C 標(biāo)準(zhǔn)格式。限制所有警告消息(除了#warnings 指示字) 。特殊情況下,一定的宏定義和擴(kuò)展不會(huì)發(fā)出警告消息。

_Pragma

通常的#pragma 指示字不能作為宏擴(kuò)展中的一部分包含進(jìn)來(lái),因此設(shè)計(jì)_Pragma 操作符是為了生成宏內(nèi)部的#pragma 指示字。為創(chuàng)建宏內(nèi)部的 poison pragma,代碼如下:_Pragma('GCC poison printf')

反斜線(xiàn)字符用作轉(zhuǎn)義字符,因此可用這種方式插入引用的字符串來(lái)創(chuàng)建 dependency
pragma:

_Pragma('GCC dependency 'lexgen.tbl'')

1.1.6 ##

可用于宏內(nèi)部將兩個(gè)源代碼權(quán)標(biāo)連接成一個(gè)的連接指示字。可用來(lái)構(gòu)造不會(huì)被解析器錯(cuò)誤解釋的名字。

1.2 預(yù)定義宏

GCC中包含了很多的預(yù)定義宏,常用的預(yù)定義宏如下:

描述

__BASE_FILE__

引用的字符串,包含的是命令行中指定源文件的完整路徑名(不一定是使用宏的所有文件)。參見(jiàn)__FILE__

__CHAR_UNSIGNED__

定義該宏用來(lái)指出目標(biāo)機(jī)器的字符數(shù)據(jù)類(lèi)型是無(wú)符號(hào)的。limits.h中用它來(lái)確定CHAR_MIN和CHAR_MAX的值

__cplusplus

只在C++程序中由定義。如果編譯程序不完全符合標(biāo)準(zhǔn),該宏定義為1,否則它會(huì)定義為標(biāo)準(zhǔn)的年和月,格式符合C中的__STDC_VERSION__

__DATA__

11個(gè)字符的引用字符串,包括編譯程序的日期。它的格式為'May 3 2017'

__FILE__

引用字符串,包含使用宏的源文件名。參見(jiàn)__BASE_FILE__

__func__

同__FUNCTION__

__FUNCTION__

引用字符串,包含當(dāng)前函數(shù)的名字

__GNUC__

該宏總是定義為編譯程序的主要版本號(hào)。例如,如果編譯程序版本
號(hào)為 3.1.2,該宏定義為 3

__GNUC_MINOR__

該宏總是定義為編譯程序的次要版本號(hào)。例如,如果編譯程序版本
號(hào)為 3.1.2,該宏定義為 1

__GNUC_PATCHLEVEL__

該宏總是定義為編譯程序的修正版本號(hào)。例如,如果編譯程序版本
號(hào)為 3.1.2,該宏定義為 2

__GNUG__

由 C++編譯程序定義。無(wú)論何時(shí)定義了__cplusplus 和__GNUC__,
就會(huì)定義該宏

__INCLUDE_LEVEL__

指出 include 文件當(dāng)前深度的整數(shù)值。該值在基本文件(命令行中指定的文件)時(shí)為 0,而每次#include 指示字輸入文件就會(huì)加 1

__LINE__

使用宏的文件的行號(hào)

__NO_INLINE__

在沒(méi)有擴(kuò)展內(nèi)嵌函數(shù)的時(shí)候,該宏定義為 1,這可能因?yàn)闆](méi)有優(yōu)化或者不允許進(jìn)行內(nèi)嵌函數(shù)

__OBJC__

如果程序被編譯成 Objective-C,該宏定義為 1

__OPTIMIZE__

無(wú)論何時(shí)只要指定任何級(jí)別的優(yōu)化處理,該宏就會(huì)定義為 1

__OPTIMIZE_SIZE__

如果設(shè)置進(jìn)行尺寸上的優(yōu)化而不是速度上的優(yōu)化,該宏就會(huì)定義為1

__REGISTER_PREFIX__

該宏為一個(gè)權(quán)標(biāo)(而不是字符串) ,它是注冊(cè)器名的前綴??捎脕?lái)編寫(xiě)能夠移植到多種環(huán)境中的匯編語(yǔ)言

__STDC__

定義為 1 指出該編譯程序符合標(biāo)準(zhǔn) C。 在編譯 C++和 Objective-C 時(shí)不定義該宏,而且在指定-traditional 選項(xiàng)的時(shí)候也不會(huì)定義該宏

__STDC_HOSTED__

定義為 1 指出'宿主'的環(huán)境(其中含有完整的標(biāo)準(zhǔn) C 庫(kù))

__STDC_VERSION__

長(zhǎng)整數(shù),指出標(biāo)準(zhǔn)版本號(hào),形式為它的年和月。例如,標(biāo)準(zhǔn)的 1999年修正版為 199901L。在編譯 C++和 Objective-C 時(shí)不會(huì)定義該宏,而且在指定-traditional 選項(xiàng)的時(shí)候也不會(huì)定義該宏

__STRICT_ANSI__

只有在命令行中指定-ansi 或-std 的時(shí)候,會(huì)定義該宏。在 GNU 頭文件中使用它來(lái)限制標(biāo)準(zhǔn)中的那些定義

__TIME__

引用 7 個(gè)字符的字符串,包含編譯程序的時(shí)間。格式為'18:10:34'

__USER_LABEL_PREFIX__

該宏是一個(gè)權(quán)標(biāo)(而不是字符串) ,用作匯編語(yǔ)言中的符號(hào)前綴。該權(quán)標(biāo)依平臺(tái)有所變化,但它通常是個(gè)下劃線(xiàn)字符

__USING_SJLJ_EXCEPTIONS__

如果異常處理機(jī)制為 setjmp 和 longjmp,該宏定義為 1

__VERSION__

完整版本號(hào)。該信息沒(méi)有特殊格式,但它至少含有主要和次要版本號(hào)


關(guān)鍵字:GCC編譯器  編譯過(guò)程  預(yù)處理 引用地址:GCC編譯器原理(三)------編譯原理三:編譯過(guò)程---預(yù)處理

上一篇:GCC編譯器原理(三)------編譯原理三:編譯過(guò)程(2-1)---編譯之詞法分析
下一篇:GCC編譯器原理(二)------編譯原理一:ELF文件(3)

推薦閱讀最新更新時(shí)間:2025-06-27 03:44

低照度CCD圖像采集及噪聲預(yù)處理
??? 摘 要: 介紹電荷耦合器件CCD,及其在低照度條件下的噪聲影響機(jī)制,并從圖像預(yù)處理的角度分析噪聲消除的可能性,最后通過(guò)現(xiàn)場(chǎng)可編程器件FPGA從硬件上實(shí)現(xiàn)低照度條件下CCD圖像采集的實(shí)時(shí)噪聲消除預(yù)處理。 ??? 關(guān)鍵詞: 低照度圖像 實(shí)時(shí)噪聲處理 電荷耦合器件(CCD) 可編程器件(FPGA)  ?八十年代后期,CCD器件進(jìn)入實(shí)用階段,得到廣泛的應(yīng)用。但直接用在低照度下的監(jiān)測(cè)和識(shí)別時(shí),信噪比急劇下降。在軍事和天文觀測(cè)中可采用專(zhuān)用的像增強(qiáng)器,但在普通的應(yīng)用中,為降低成本一般通過(guò)計(jì)算機(jī)進(jìn)行圖像處理提高信噪比。本文提供一種折衷的方案,通過(guò)分析CCD的特點(diǎn),采用硬件的方法實(shí)現(xiàn)圖像增強(qiáng),為計(jì)算機(jī)后端減少了大量復(fù)
[應(yīng)用]
小廣播
設(shè)計(jì)資源 培訓(xùn) 開(kāi)發(fā)板 精華推薦

最新單片機(jī)文章

 
EEWorld訂閱號(hào)

 
EEWorld服務(wù)號(hào)

 
汽車(chē)開(kāi)發(fā)圈

 
機(jī)器人開(kāi)發(fā)圈

電子工程世界版權(quán)所有 京ICP證060456號(hào) 京ICP備10001474號(hào)-1 電信業(yè)務(wù)審批[2006]字第258號(hào)函 京公網(wǎng)安備 11010802033920號(hào) Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 乐清市| 海城市| 侯马市| 会昌县| 牟定县| 新宁县| 调兵山市| 雷山县| 四会市| 海兴县| 定陶县| 元谋县| 钟山县| 兴海县| 长海县| 大厂| 和林格尔县| 太仓市| 宁津县| 柳州市| 正安县| 太白县| 平凉市| 教育| 承德市| 太原市| 雅安市| 云浮市| 和顺县| 大英县| 永顺县| 进贤县| 皮山县| 易门县| 东莞市| 邹城市| 屯昌县| 浮山县| 蒲江县| 诏安县| 平遥县|