當(dāng)前位置:首頁 > 廠商動態(tài) > IAR
[導(dǎo)讀]在嵌入式開發(fā)中,代碼的體積和運行效率非常重要,代碼體積往往和芯片的FLASH、RAM容量對應(yīng),程序的運行效率也要求在相應(yīng)能力的處理器上運行。在大多數(shù)情況下,成熟的開發(fā)人員都希望降低代碼體積、提高代碼運行效率,然而具體該怎么做呢?本篇文章將以國際知名編譯器廠商IAR Systems的編譯器為例,來解答開發(fā)人員在實際工作中常常遇到的問題,工程師朋友們可以在IAR編譯器上進行實踐驗證。

嵌入式開發(fā)中,代碼的體積和運行效率非常重要,代碼體積往往和芯片的FLASH、RAM容量對應(yīng),程序的運行效率也要求在相應(yīng)能力的處理器上運行。在大多數(shù)情況下,成熟的開發(fā)人員都希望降低代碼體積、提高代碼運行效率,然而具體該怎么做呢?本篇文章將以國際知名編譯器廠商IAR Systems的編譯器為例,來解答開發(fā)人員在實際工作中常常遇到的問題,工程師朋友們可以在IAR編譯器上進行實踐驗證。

對于嵌入式系統(tǒng),最終代碼的體積和效率取決于由編譯器生成的可執(zhí)行代碼,而非開發(fā)人員編寫的源代碼;但是源代碼的優(yōu)化,可以幫助編譯器生成更加優(yōu)質(zhì)的可執(zhí)行代碼。因此,開發(fā)人員不僅要從整體效率等因素上去構(gòu)思源代碼體系,也要高度關(guān)注編譯器的性能和編譯優(yōu)化的便捷性。

有優(yōu)化功能的編譯器可生成既小又快的可執(zhí)行代碼,編譯器是通過對源代碼的重復(fù)轉(zhuǎn)換來實現(xiàn)優(yōu)化。通常,編譯器優(yōu)化會遵循完善的數(shù)學(xué)或邏輯理論基礎(chǔ)。但是某些編譯優(yōu)化則是通過啟發(fā)式的方法,經(jīng)驗表明,一些代碼轉(zhuǎn)換往往會產(chǎn)生更好的代碼,或者開拓出進一步編譯優(yōu)化的空間。

編譯優(yōu)化只有少數(shù)情況依賴于編譯器的黑科技,大多數(shù)時候編寫源代碼的方式?jīng)Q定了程序是否可以被編譯器優(yōu)化。在某些情況下,即使對源代碼做微小改動也會對編譯器生成的代碼效率產(chǎn)生重大影響。

本文將講述在編寫代碼時需要注意的事項,但我們首先應(yīng)明確一點,我們沒有必要盡量減少代碼量,因為即使在一個表達式中使用 ?:- 表達式、后增量和逗號表達式來消除副作用,也不會使編譯器產(chǎn)生更有效的代碼。這只會使你的源代碼變得晦澀難懂,難以維護。例如在一個復(fù)雜的表達式中間加入一個后增量或賦值,則在讀代碼的時候很容易被忽略。請盡量用一種易于閱讀的風(fēng)格來編寫代碼。

循環(huán)

下面看似簡單的循環(huán)會報錯嗎?

for(i =0; i != n;++i)

{

a[i]= b[i];

}

雖然不會報錯,但其中有幾點會影響到編譯器生成的代碼效率。

例如,索引變量的類型應(yīng)與指針相匹配。

像 a[i] 這樣的數(shù)組表達式實際上是 *(&a[0]+i*sizeof(a[0]),或者通俗地說:將第 i個元素的偏移量加到 a 的第一個元素的指針上。對于指針運算, 索引表達式的類型最好與指針?biāo)赶虻念愋鸵恢拢╛_far 指針除外,因為其指針?biāo)赶虻念愋秃退饕磉_式的類型不同)。如果索引表達式的類型與指針?biāo)赶虻念愋筒黄ヅ洌敲丛诎阉c指針相加之前,必須將它強制轉(zhuǎn)換為正確的類型。

如果在應(yīng)用中,堆棧空間資源(堆棧一般放在RAM中)比代碼尺寸資源(代碼一般放在ROM或者Flash中)更寶貴,則可以為索引變量選擇一個更小的類型來減少堆棧空間的使用,但這往往會犧牲代碼尺寸和執(zhí)行時間(代碼尺寸變大,執(zhí)行時間變慢)。不僅如此,這種轉(zhuǎn)換也會妨礙循環(huán)代碼的優(yōu)化。

除上述問題外,我們也要關(guān)注循環(huán)條件,因為只有在進入循環(huán)之前可以計算出迭代次數(shù)的情況下,才可以進行循環(huán)優(yōu)化。然而,這項計算工作非常復(fù)雜,并非用最終值減去初始值并除以增量那么簡單。例如,如果 i 是一個無符號字符,n 是一個整數(shù),而 n 的值是 1000,那么會發(fā)生什么情況?答案是變量 i 在達到 1000 之前就會溢出。

雖然程序員肯定不想要一個無限循環(huán),重復(fù)地將 256 個元素從 b 復(fù)制到 a,但是編譯器無法了解程序員的意圖。它必須假設(shè)最壞的情況,并且不能應(yīng)用需要在進入循環(huán)之前提供行程數(shù)的優(yōu)化。此外,如果最終值是一個變量,您還應(yīng)該避免在循環(huán)條件中使用關(guān)系運算符 <= 和 >=。如果循環(huán)條件是 i <= n,那么 n 有可能是該類型中可表示的最高值,因此編譯器必須假定這是一個潛在的無限循環(huán)。

別名

通常,我們不建議使用全局變量。這是因為您可在程序的任何地方修改全局變量,并且程序會因全局變量的值而變化。這就會形成復(fù)雜的依賴關(guān)系,使人很難理解程序,也很難確定改變?nèi)肿兞康闹禃Τ绦虍a(chǎn)生怎樣的影響。從優(yōu)化器的角度來看,這種情況更糟糕,因為通過指針的存儲就可以改變?nèi)我馊肿兞康闹怠H绻芡ㄟ^多種方式訪問一個變量,這種情況就會被稱為別名,而別名使代碼更難優(yōu)化。

char*buf

voidclear_buf()

{

int i;

for(i =0; i <128;++i)

{

buf[i]=0;

}

}

盡管程序員知道向 buf 所指向的緩存區(qū)進行寫操作不會改變這個buf變量本身,但編譯器還是不得不做最壞的打算,在循環(huán)的每一次迭代中從內(nèi)存中重新加載 buf。

如果將緩存區(qū)的地址作為參數(shù)傳遞,而不是使用全局變量,則可以消除別名:

voidclear_buf(char*buf)

{

int i;

for(i =0; i <128;++i)

{

buf[i]=0;

}

}

使用這個解決方案后,指針 buf 就不會被通過指針的存儲影響。如此一來,指針 buf 在循環(huán)中就可以保持不變,其值只需在循環(huán)前加載一次即可,而不是在每次迭代時都要重新加載。

然而,如果需要在不共享調(diào)用者/被調(diào)用者關(guān)系的代碼段之間傳遞信息,則直接使用全局變量即可。但是,對于計算密集型任務(wù),尤其是涉及指針操作時,最好使用自動變量。

盡量不用后增量和后減量

在下文中,關(guān)于后增量的所有內(nèi)容也適用于后減量。C 語言中關(guān)于后增量語義的標(biāo)準(zhǔn)文本指出:“后綴 ++ 運算符的結(jié)果是操作數(shù)的值。在得到結(jié)果后,操作數(shù)的值會遞增”。雖然微控制器普遍擁有可在加載或存儲操作后增加指針的尋址模式,但其中只有很少能以同樣的效率處理其他類型的后增量。為符合標(biāo)準(zhǔn),編譯器必須在執(zhí)行增量之前將操作數(shù)復(fù)制到一個臨時變量。對于直線代碼來說,可以從表達式中取出增量,然后放在表達式之后。比如以下表達式:

foo = a[i++];

可以改為

foo = a[i];

i = i +1;

但如果后增量屬于 while 循環(huán)中的條件,又會發(fā)生什么?由于在條件后面沒有可以插入增量的地方,因此必須在測試前添加增量。對于這些常見但是又與生成可執(zhí)行代碼效率密切相關(guān)的設(shè)計,諸如IAR Systems的Embedded Workbench這樣的工具都在總結(jié)了大量實踐后提供了優(yōu)化方案。

比如以下循環(huán)

i =0;

while(a[i++]!=0)

{

...

}

應(yīng)改為

loop:

temp = i;/* 保存操作數(shù)的值 */

i = temp +1;/* 遞增操作數(shù) */

if(a[temp]==0)/* 使用保存的值 */

goto no_loop;

...

goto loop;

no_loop:

loop:

temp = a[i];/* 使用操作數(shù)的值 */

i = i +1;/* 遞增操作數(shù) */

if(temp ==0)

goto no_loop;

...

goto loop;

no_loop:

如果循環(huán)后的 i 的值不相關(guān),最好將增量放在循環(huán)內(nèi)。比如以下幾乎相同的循環(huán)

i =0;

while(a[i]!=0)

{

++i;

...

}

可以在沒有臨時變量的情況下執(zhí)行:

loop:

if(a[i]==0)

goto no_loop;

i = i +1;

...

goto loop;

no_loop:

優(yōu)化編譯器的開發(fā)者們很清楚后增量會使代碼編寫變得更復(fù)雜,盡管我們已盡力去識別這些模式,并盡量消除臨時變量,但總有一些情況使我們無法產(chǎn)生有效代碼,尤其是遇到比上述更復(fù)雜的循環(huán)條件時。通常,我們會將一個復(fù)雜的表達式分割成若干個更簡單的表達式,就像上面的循環(huán)條件被分割成一個測試和一個增量那樣。

在 C++ 環(huán)境中,選擇前增量還是后增量的重要性更高。這是因為 operator++ 和 operator-- 都可以以前綴和后綴的形式重載。將運算符作為類對象重載時,雖然沒必要模仿基本類型運算符的行為,但也應(yīng)盡量接近。因此,對于那些可以直觀地對對象進行遞增和遞減的類,例如迭代器,通常會有前綴(operator++() 和 operator--())和后綴形式(operator++(int) 和 operator--(int))。

為了模擬基本類型的前綴 ++ 的行為,operator++() 可以修改對象并返回對修改后對象的引用。那么模擬基本類型的后綴 ++ 的行為會怎樣?您還記得嗎?“后綴 ++ 運算符的結(jié)果是操作數(shù)的值。在得到結(jié)果后,操作數(shù)的值會遞增”。就像上面的非直線代碼一樣,operator++(int) 的實現(xiàn)者必須復(fù)制原始對象,修改原始對象,并按值返回副本。由于存在復(fù)制操作,因此 operator++(int) 的開銷要高于 operator++()。

對于基本類型,如果忽略 i++ 的結(jié)果,優(yōu)化器通常可以消除不必要的復(fù)制,但優(yōu)化器不能將對一個重載運算符的調(diào)用變?yōu)榱硪粋€。如果您出于習(xí)慣編寫 i++ 而不是 ++i,您就會調(diào)用開銷更大的增量運算符。

雖然我們一直在反對使用后增量,但不得不承認(rèn),后增量在有些情況下還是有用的。如果確實要給一個變量進行后置增量操作,那就繼續(xù)吧。如果后增量操作和您期望的操作一致,可以使用后增量操作。但請注意,切勿為避免多寫一行代碼來遞增變量,而使用后增量操作。

每當(dāng)您在循環(huán)條件、if 條件、switch 表達式、?:- 表達式或函數(shù)調(diào)用參數(shù)中添加不必要的后增量時,都會使編譯器不得不生成更大、更慢的代碼。這個清單是不是太長了,記不?。拷裉炀烷_始培養(yǎng)好的習(xí)慣吧!在使用后增量操作前,先問問自己能不能把增量操作作為下一條語句。

結(jié)語

當(dāng)然,軟件開發(fā)工作并不是只要求開發(fā)人員去“將就”編譯器,他們與編譯器之間的相互協(xié)同是快速而高效地完成編程工作的基礎(chǔ)之一。此外,從編譯器的發(fā)展過程來看,它們不僅要跟隨技術(shù)和語言的演進而迭代和創(chuàng)新,而且還要廣泛參考更多的開發(fā)習(xí)慣,那些歷史更悠久、使用更廣泛的編譯器可以為開發(fā)人員帶來更高的效率。

因此,在了解了如何編寫利于一款優(yōu)秀編譯器優(yōu)化的代碼之后,用戶們的工作效率就可以事半功倍。本文中提到的這些原理和tips,也是IAR Systems這樣的公司長時間總結(jié)的最優(yōu)實踐,而且都可以在該公司的Embedded Workbench中進行驗證和探索,在其工具界面中可以查看代碼的執(zhí)行時間和代碼尺寸,從而找到最佳解決方案。

好的工具除了通用的代碼編譯優(yōu)化,還支持高度靈活的自定義優(yōu)化設(shè)置,如IAR Embedded Workbench包含針對運行效率和代碼體積的不同優(yōu)化等級,對于不同的應(yīng)用需求,還可以設(shè)置從整個工程,到每個源代碼文件,甚至是每個函數(shù)的優(yōu)化等級,幫助工程師為自己的應(yīng)用適配出最佳的優(yōu)化方案。希望此篇文章對于開發(fā)人員更深度地了解程序優(yōu)化有所幫助。


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

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉