點(diǎn)擊上方藍(lán)字關(guān)注我們首先,問大家一個問題:你們寫單片機(jī)程序【死循環(huán)】時,喜歡用 for(;;) 還是 while(1)? 快來為你喜歡用的【死循環(huán)】打call,評論區(qū)等你哦~一位工程師發(fā)現(xiàn),國外工程師在給demo在做死循環(huán)時用的是for(;;),而不是常用的while(1)。這僅僅是個人習(xí)慣的問題,還是有更深層次的含義?
一、沒啥區(qū)別黨:都是心理作用
大部分網(wǎng)友認(rèn)為二者并沒有什么區(qū)別,很多時候,只是心理作用,國外工程師認(rèn)為while需要經(jīng)過判斷括號里的表達(dá)式是否非0才跳轉(zhuǎn)。但經(jīng)過編譯器的精心優(yōu)化以后,while(1)也會被優(yōu)化成無條件跳轉(zhuǎn)(jmp指令),所以跟for(;;)沒什么區(qū)別。有人表示,for(;;)在英語母語者那里很容易跟forever掛鉤。網(wǎng)友解析,也很有可能是習(xí)慣問題,其實(shí)while(1),還是for(;;)兩個語法上有啥區(qū)別,那就是for(;;) 明確就是循環(huán),等價于goto一直跳,沒有比較條件。while不編譯支持優(yōu)化的前提下都需要做cmp運(yùn)算設(shè)置寄存器ZF,才能jne,je指令條件跳轉(zhuǎn)。而for(;;)就是明確的jmp無條件轉(zhuǎn)移eip,沒有jne,je條件跳轉(zhuǎn)。不過其實(shí)無所謂的,這根本不能提高任何一點(diǎn)代碼執(zhí)行的性能。因?yàn)楝F(xiàn)代編譯器大多優(yōu)化以后跟for(;;)的結(jié)果沒得什么區(qū)別。其實(shí)你所考慮到的一切優(yōu)化手段,編譯器都能幫你完成,因?yàn)榫幾g器(尤其是開源的GCC和LLVM)是由來自全球各地的程序員共同研發(fā)并改進(jìn)的,它們的優(yōu)化能力遠(yuǎn)遠(yuǎn)強(qiáng)于你手動改進(jìn)代碼。也有網(wǎng)友“Shuax”使用mingw編譯,實(shí)地測試一番:for版本:
#include int main(){ for(;;) { printf("for\n"); }}
生成匯編:while版本:
#includeintmain(){ while(1) { printf("while\n"); }}
生成匯編: 你會發(fā)現(xiàn),除了文件名不同,其余都相同。當(dāng)然,這里額外說一下,不同代碼、不同編譯器,以及不同優(yōu)化等級,可能最終結(jié)果有所差異。
二、正方觀點(diǎn):哪有好的編譯器
不過,有人跳出來反駁,現(xiàn)代編譯器的確優(yōu)化很好,二者運(yùn)行起來沒啥區(qū)別,但是實(shí)際在嵌入式工作中,尤其是MCU編程中,可沒有那么好的編譯器。一位工程師表示,很多嵌入式設(shè)備只有專用的編譯器,而過去這些編譯器,尤其是嵌入式編譯器沒做好優(yōu)化的情況下,while(1)要比for(;;)多幾個語句。因?yàn)閣hile里面是判斷啊,就會變成:
label: …… mov a, #1 jnz label
這種情況而for(;;)的話一般只會是jmp label。許多人也有類似的經(jīng)歷,并表示,有些私有編譯器連 (int)a<<0 這種都能生成非法指令,不由地懷疑配套的破芯片到底能不能受得了各種優(yōu)化過的指令。
三、反方觀點(diǎn):這種代碼過時了
也有工程師呼吁,不要學(xué)習(xí)這種編碼風(fēng)格,現(xiàn)在已經(jīng)是2024年了,用for(;;)表示無限循環(huán)已是一種過時的風(fēng)格了。從施特勞斯特擼普博士到我國國家軍用標(biāo)準(zhǔn),均認(rèn)為 for(;;)?是一種不良風(fēng)格,可參見:
- GJB 8114-2013 R-1-9-4:無限循環(huán)必須使用while(1)語句,禁止使用for(;;)等其他形式
- CppCoreGuidelines ES.73:Prefer a while-statement to a for-statement when there is no obvious loop variable
- 360 safe rules: for語句沒有明確的循環(huán)變量時應(yīng)改用while句語
這是為什么呢?在較為嚴(yán)格的規(guī)范體系內(nèi),for 語句專用于實(shí)現(xiàn)具有明確循環(huán)次數(shù)和循環(huán)變量的迭代算法,小括號內(nèi)的三個表達(dá)式應(yīng)分別專注于循環(huán)變量的初始化、循環(huán)條件的判斷、循環(huán)變量的增減,這樣可以使循環(huán)具有清晰的靜態(tài)結(jié)構(gòu),便于閱讀,利于維護(hù)。如果沒有明確的循環(huán)變量,則應(yīng)改用 while 循環(huán),避免對代碼的維護(hù)者造成誤導(dǎo)。有人說for(;;)表示無條件循環(huán),while(1)需要作條件判斷,效率比for(;;)慢,有一定道理,但那都是很早以前的事情了,現(xiàn)在即使沒有編譯器優(yōu)化,這種開銷也不會成為效率的瓶頸,是不值得優(yōu)化的,保持代碼清晰的靜態(tài)結(jié)構(gòu)更為重要!
四、工程師實(shí)地測試:和編譯器和優(yōu)化有關(guān)
公眾號博主“WKJay”也在STM32F103、ARMCC5進(jìn)行過測試,將兩個邏輯分別運(yùn)行一下(不開編譯器優(yōu)化),查看邏輯分析儀輸出的結(jié)果。while(1) 邏輯運(yùn)行結(jié)果: for(;;) 邏輯運(yùn)行結(jié)果: 結(jié)果顯示,雖然循環(huán)體完全相同,但實(shí)際運(yùn)行結(jié)果來看,for(;;) 語句執(zhí)行得更快(45.863ms),比 while(1)(48.643ms) 快了5.7%左右。根據(jù)他的分析,for的指令更精簡,而while的指令相對更繁瑣,簡而言之,for抄了近道,而while彎彎繞繞。
最后,他開啟了編譯器的O3優(yōu)化,結(jié)果,二者就幾乎不存在差別了(12.505ms): 從可讀性角度來說,while(1)簡單清晰,for(;;)就模糊多了。不過,對于一些比較老的專用編譯器來說,可能就需要慎重考慮使用哪種形式。
對現(xiàn)代編譯器來說,二者完全就是一回事,更何況,高主頻的芯片不在乎一兩條機(jī)器指令了,所以這種情況下,怎么順眼就怎么寫。本文轉(zhuǎn)載自公眾號|strongerHuang如有侵權(quán) |聯(lián)系刪除
-
單片機(jī)
+關(guān)注
關(guān)注
6030文章
44489瀏覽量
631960 -
mcu
+關(guān)注
關(guān)注
146文章
16885瀏覽量
349914 -
循環(huán)
+關(guān)注
關(guān)注
0文章
92瀏覽量
15947
發(fā)布評論請先 登錄
相關(guān)推薦
評論