日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁(yè) > > 嵌入式微處理器
[導(dǎo)讀]當(dāng)使用參數(shù)調(diào)用宏時(shí),會(huì)將參數(shù)替換為宏主體,并與其他輸入文件一起檢查結(jié)果,以進(jìn)行更多的宏調(diào)用,可以將部分來(lái)自宏主體和部分自變量的宏調(diào)用組合在一起。


語(yǔ)法錯(cuò)誤

當(dāng)使用參數(shù)調(diào)用宏時(shí),會(huì)將參數(shù)替換為宏主體,并與其他輸入文件一起檢查結(jié)果,以進(jìn)行更多的宏調(diào)用,可以將部分來(lái)自宏主體和部分自變量的宏調(diào)用組合在一起。例如,

#define?twice(x)?(2*(x))
#define?call_with_1(x)?x(1)
call_with_1?(twice)

//x=1
?→?twice(1)
?→?(2*(1))

宏定義不必帶有括號(hào),通過(guò)在宏主體中編寫(xiě)不平衡的開(kāi)放括號(hào),可以創(chuàng)建一個(gè)從宏主體內(nèi)部開(kāi)始但在宏主體外部結(jié)束的宏調(diào)用。例如,

#define?strange(file)?fprintf?(file,?"%s?%d",

strange(stderr)?p,?35)
?????→?fprintf?(stderr,?"%s?%d",?p,?35)

組合宏調(diào)用的功能可能會(huì)很有用,但是在宏主體中使用不平衡的開(kāi)放括號(hào)只會(huì)造成混淆,應(yīng)該避免。

運(yùn)算符優(yōu)先級(jí)問(wèn)題

在大多數(shù)宏定義示例中,每次出現(xiàn)的宏參數(shù)名稱(chēng)都帶有括號(hào),并且另一對(duì)括號(hào)通常會(huì)包圍整個(gè)宏定義,這是編寫(xiě)宏最好的方式。舉個(gè)例子

#define?ceil_div(x,?y)?(x?+?y?-?1)?/?y

假定其用法如下:

a?=?ceil_div(b&c,sizeof(int));

拓展開(kāi)是

a?=(b&c?+?sizeof(int)-1)/?sizeof(int);

這沒(méi)有達(dá)到我們的預(yù)期,C的運(yùn)算符優(yōu)先級(jí)規(guī)則使其等效于此,而我們想要的是:

a?=(((b&c)+?sizeof(int)-1))/?sizeof(int);

如果我們將宏定義為

#define?ceil_div(x,y)((x)+(y)-1)/(y)

可能導(dǎo)致另一種情況,sizeof ceil_div(1,2)是一個(gè)C表達(dá)式,可以計(jì)算ceil_div(1,2)類(lèi)型的大小,它擴(kuò)展為:

sizeof((1)+(2)-1)/(2)

這將采用整數(shù)的大小并將其除以2,而除法包含在內(nèi)部的sizeof之外。所以整個(gè)宏定義的括號(hào)可防止此類(lèi)問(wèn)題。那么,下面是定義ceil_div的正確方法如下

#define?ceil_div(x,y)((((x)+(y)-1)/(y))

吞噬分號(hào)

通常需要定義一個(gè)擴(kuò)展為復(fù)合語(yǔ)句的宏。例如,考慮以下宏,該宏跨空格字符前進(jìn)一個(gè)指針(參數(shù)p表示在何處查找):

#define?SKIP_SPACES(p,?limit)??\
{?char?*lim?=?(limit);?????????\
??while?(p?????if?(*p++?!=?'?')?{?????????\
??????p--;?break;?}}}

該宏定義必須是單個(gè)邏輯行,嚴(yán)格來(lái)說(shuō),該調(diào)用擴(kuò)展為復(fù)合語(yǔ)句,這是一個(gè)完整的語(yǔ)句,不需要用分號(hào)結(jié)束。

但是,由于它看起來(lái)像函數(shù)調(diào)用,因此,如果可以像使用函數(shù)調(diào)用一樣使用它,則可以最大程度地減少混亂,然后再寫(xiě)一個(gè)分號(hào),就像在SKIP_SPACES(p,lim)中一樣。

這可能會(huì)在else語(yǔ)句之前出問(wèn)題,因?yàn)榉痔?hào)實(shí)際上是空語(yǔ)句。假設(shè)你寫(xiě)

if?(*p?!=?0)
??SKIP_SPACES?(p,?lim);
else?…

在if條件和else條件之間存在兩個(gè)語(yǔ)句(復(fù)合語(yǔ)句和null語(yǔ)句)使C代碼無(wú)效。

怎么解決?我們可以使用do…while語(yǔ)句更改宏SKIP_SPACES的定義以解決此問(wèn)題。方法如下:

#define?SKIP_SPACES(p,?limit)?????\
do?{?char?*lim?=?(limit);?????????\
?????while?(p????????if?(*p++?!=?'?')?{?????????\
?????????p--;?break;?}}}??????????\
while?(0)

SKIP_SPACES (p, lim);擴(kuò)展為

do?{…}?while?(0);

這是一個(gè)陳述,循環(huán)僅執(zhí)行一次,而且大多數(shù)編譯器不會(huì)為此生成任何額外的代碼。

重復(fù)調(diào)用

我們常見(jiàn)的“最小”定義一個(gè)宏min,如下所示:

#define?min(X,?Y)??((X)?

當(dāng)將此宏與包含副作用的參數(shù)一起使用時(shí),如此處所示,

next?=?min(x?+?y,foo(z));

它擴(kuò)展如下:

next?=?((x?+?y)?

其中x + y替換了X,而foo(z)替換了Y。

函數(shù)foo出現(xiàn)在程序中的語(yǔ)句中僅使用一次,但是表達(dá)式foo(z)已兩次替換到宏擴(kuò)展中。結(jié)果,執(zhí)行該語(yǔ)句時(shí)可能會(huì)兩次調(diào)用foo,所以min是一個(gè)不安全的宏。

解決此問(wèn)題的最佳方法是以僅計(jì)算一次foo(z)值的方式定義min。C語(yǔ)言沒(méi)有提供執(zhí)行此操作的標(biāo)準(zhǔn)方法,但是可以使用GNU擴(kuò)展來(lái)完成此操作,如下所示:

#define?min(X,?Y)????????????????\
({?typeof?(X)?x_?=?(X);??????????\
???typeof?(Y)?y_?=?(Y);??????????\
???(x_?

“({{…})”符號(hào)產(chǎn)生一個(gè)復(fù)合表達(dá)式,它的值是其最后一條語(yǔ)句的值。

如果不使用GNU C擴(kuò)展,唯一的解決方案是在使用宏min時(shí)要小心。例如計(jì)算foo(z)的值時(shí),將其保存在變量中,然后在min中使用該變量:

//假設(shè)foo返回int類(lèi)型
#define?min(X,?Y)??((X)?

{
??int?tem?=?foo?(z);
??next?=?min?(x?+?y,?tem);
}

自引用宏

自引用宏是其名稱(chēng)出現(xiàn)在其定義中的宏。我們知道所有宏定義都將被重新掃描以查找更多要替換的宏,如果自引用被認(rèn)為是宏的使用,它將產(chǎn)生無(wú)限大的擴(kuò)展。

為防止這種情況,自引用不被視為宏調(diào)用。它原樣傳遞到預(yù)處理器輸出中。舉個(gè)例子

#define?foo?(4?+?foo)

按照普通規(guī)則,其宏定義分析如下

  1. 對(duì)foo的每個(gè)引用都將擴(kuò)展為(4 + foo);

  2. 然后將對(duì)其進(jìn)行重新掃描,并將其擴(kuò)展為(4 +(4 + foo));

  3. 以此類(lèi)推,直到計(jì)算機(jī)內(nèi)存耗盡。

自引用規(guī)則將這一過(guò)程縮短了一步,即(4 + foo),因此此宏定義可能會(huì)導(dǎo)致程序在引用foo的任何地方將foo的值加4。

閱讀程序的人看到foo是變量,就難以記得它也是宏,真的會(huì)坑爹的。它的一種常見(jiàn)有用用法是創(chuàng)建一個(gè)可擴(kuò)展為其自身的宏。如果你寫(xiě)

#define?EPERM?EPERM

然后宏EPERM擴(kuò)展為EPERM。實(shí)際上,每當(dāng)在運(yùn)行文本中使用預(yù)處理器時(shí),預(yù)處理器都會(huì)將其單獨(dú)保留。

如果宏x擴(kuò)展為使用宏y,而y的擴(kuò)展引用了宏x,則這是x的間接自引用。在這種情況下,x也不展開(kāi),舉個(gè)例子

#define?x?(4?+?y)
#define?y?(2?*?x)

然后x和y擴(kuò)展如下:

x→(4?+?y)
?????→(4?+(2?*?x))

y→(2?*?x)
?????→(2?*(4?+?y))

當(dāng)每個(gè)宏出現(xiàn)在另一個(gè)宏的定義中時(shí),它們將被展開(kāi),但是當(dāng)它間接出現(xiàn)在其自己的定義中時(shí),則不會(huì)被展開(kāi)。

參數(shù)預(yù)掃描處理

宏參數(shù)在被替換為宏主體之前必須經(jīng)過(guò)完全宏擴(kuò)展,替換后,將再次掃描整個(gè)宏主體,包括替換的參數(shù),以查找要擴(kuò)展的宏。

如果參數(shù)包含任何宏調(diào)用,則它們將在第一次掃描時(shí)擴(kuò)展,那么結(jié)果不包含任何宏調(diào)用,因此第二次掃描不會(huì)更改它。

如果按照給定的方式替換了參數(shù),并且沒(méi)有進(jìn)行預(yù)掃描,則剩余的單個(gè)掃描將找到相同的宏調(diào)用并產(chǎn)生相同的結(jié)果。

預(yù)掃描處理在以下三種特殊情況下有大的作用。

對(duì)宏的嵌套調(diào)用

當(dāng)宏的參數(shù)包含對(duì)該宏的調(diào)用時(shí),就會(huì)發(fā)生對(duì)宏的嵌套調(diào)用,舉個(gè)例子。

如果f是期望一個(gè)參數(shù)的宏,則f(f(1))是對(duì)f的嵌套調(diào)用對(duì)。通過(guò)擴(kuò)展f(1)并將其代入f的定義來(lái)進(jìn)行所需的擴(kuò)展。預(yù)掃描會(huì)導(dǎo)致發(fā)生預(yù)期的結(jié)果。

如果沒(méi)有預(yù)掃描,f(1)本身將被替換為參數(shù),并且f的內(nèi)部使用將在主掃描期間作為間接自引用出現(xiàn),并且不會(huì)擴(kuò)展。

調(diào)用其他可進(jìn)行字符串化或連接的宏的宏

如果參數(shù)是字符串化或串聯(lián)的,則不會(huì)進(jìn)行預(yù)掃描。

如果要擴(kuò)展宏,然后對(duì)其擴(kuò)展進(jìn)行字符串化或串聯(lián),則可以通過(guò)使一個(gè)宏調(diào)用進(jìn)行該字符串化或串聯(lián)的另一宏來(lái)實(shí)現(xiàn)。舉個(gè)例子

#define?AFTERX(x)?X_?##?x
#define?XAFTERX(x)?AFTERX(x)
#define?TABLESIZE?1024
#define?BUFSIZE?TABLESIZE

然后AFTERX(BUFSIZE)擴(kuò)展為X_BUFSIZE,而XAFTERX(BUFSIZE)擴(kuò)展為X_1024而不是X_TABLESIZE,預(yù)掃描始終會(huì)進(jìn)行完整的擴(kuò)展。

參數(shù)中使用的宏,其擴(kuò)展名包含未屏蔽的逗號(hào)。

這可能導(dǎo)致使用錯(cuò)誤數(shù)量的參數(shù)調(diào)用在第二次掃描時(shí)擴(kuò)展的宏。舉個(gè)例子

#define?foo??a,b
#define?bar(x)?lose(x)
#define?lose(x)?(1?+?(x))

我們預(yù)期的結(jié)果是bar(foo)變成(1 +(foo)),然后變成(1 +(a,b))

然而bar(foo)擴(kuò)展為loss(a,b)會(huì)出錯(cuò),因?yàn)長(zhǎng)os需要一個(gè)參數(shù)。在這種情況下,該問(wèn)題可以通過(guò)使用相同的括號(hào)輕松解決,該括號(hào)應(yīng)用于防止算術(shù)運(yùn)算的錯(cuò)誤嵌套:

#define?foo?(a,b)
or
#define?bar(x)?lose((x))

多余的一對(duì)括號(hào)可防止foo定義中的逗號(hào)被解釋為參數(shù)分隔符。

參數(shù)中的換行符

類(lèi)似函數(shù)的宏的調(diào)用可以擴(kuò)展到許多邏輯行,但是在本實(shí)施方式中,整個(gè)擴(kuò)展是一行完成的。

因此,由編譯器或調(diào)試器發(fā)出的行號(hào)是指調(diào)用在其上開(kāi)始的行,這可能與包含導(dǎo)致問(wèn)題的參數(shù)的行不同,例如:

#define?ignore_second_arg(a,b,c)?a;?c

ignore_second_arg?(foo?(),
???????????????????ignored?(),
???????????????????syntax?error);

Syntax error on tokens觸發(fā)的語(yǔ)法錯(cuò)誤會(huì)導(dǎo)致錯(cuò)誤消息引用第三行(ignore_second_arg行),即使有問(wèn)題的代碼來(lái)自第五行。

參考資料:

http://gcc.gnu.org/onlinedocs/cpp/Macros.html



-END-


來(lái)源 | 技術(shù)讓夢(mèng)想更偉大

作者 | 李肖遙


|?整理文章為傳播相關(guān)技術(shù),版權(quán)歸原作者所有?|

|?如有侵權(quán),請(qǐng)聯(lián)系刪除?|


【1】嵌入式研發(fā)10多年,工程師悟出這些道理

【2】當(dāng)談起嵌入式工程師,究竟在談些什么

【3】嵌入式工程師出路之我見(jiàn):就業(yè),技術(shù),行業(yè)...

【4】為什么嵌入式工程師會(huì)對(duì)8位MCU有誤解?

【5】嵌入式工程師結(jié)合經(jīng)歷聊硬件工程師和軟件工程師哪個(gè)更有前途?



免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺(tái)立場(chǎng),如有問(wèn)題,請(qǐng)聯(lián)系我們,謝謝!

嵌入式ARM

掃描二維碼,關(guān)注更多精彩內(nèi)容

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專(zhuān)欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問(wèn)題卻十分常見(jiàn),不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問(wèn)題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(chē)(EV)作為新能源汽車(chē)的重要代表,正逐漸成為全球汽車(chē)產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車(chē)的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車(chē)的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車(chē) 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車(chē)場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問(wèn)題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周?chē)娮釉O(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開(kāi)關(guān)電源具有效率高的特性,而且開(kāi)關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開(kāi)關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉