首先,問(wèn)大家一個(gè)問(wèn)題:你們寫(xiě)單片機(jī)程序【死循環(huán)】時(shí),喜歡用用 for(;;) 還是 while(1)?
一位工程師發(fā)現(xiàn),國(guó)外工程師在給demo在做死循環(huán)時(shí)用的是for(;;),而不是常用的while(1)。這僅僅是個(gè)人習(xí)慣的問(wèn)題,還是有更深層次的含義?
沒(méi)啥區(qū)別黨:都是心理作用
大部分網(wǎng)友認(rèn)為二者并沒(méi)有什么區(qū)別,很多時(shí)候,只是心理作用,國(guó)外工程師認(rèn)為while需要經(jīng)過(guò)判斷括號(hào)里的表達(dá)式是否非0才跳轉(zhuǎn)。但經(jīng)過(guò)編譯器的精心優(yōu)化以后,while(1)也會(huì)被優(yōu)化成無(wú)條件跳轉(zhuǎn)(jmp指令),所以跟for(;;)沒(méi)什么區(qū)別。 ? 有人表示,for(;;)在英語(yǔ)母語(yǔ)者那里很容易跟forever掛鉤。 ? 網(wǎng)友解析,也很有可能是習(xí)慣問(wèn)題,其實(shí)while(1),還是for(;;)兩個(gè)語(yǔ)法上有啥區(qū)別,那就是for(;;) 明確就是循環(huán),等價(jià)于goto一直跳,沒(méi)有比較條件。 ? while不編譯支持優(yōu)化的前提下都需要做cmp運(yùn)算設(shè)置寄存器ZF,才能jne,je指令條件跳轉(zhuǎn)。而for(;;)就是明確的jmp無(wú)條件轉(zhuǎn)移eip,沒(méi)有jne,je條件跳轉(zhuǎn)。 ? 不過(guò)其實(shí)無(wú)所謂的,這根本不能提高任何一點(diǎn)代碼執(zhí)行的性能。因?yàn)楝F(xiàn)代編譯器大多優(yōu)化以后跟for(;;)的結(jié)果沒(méi)得什么區(qū)別。 ? 其實(shí)你所考慮到的一切優(yōu)化手段,編譯器都能幫你完成,因?yàn)榫幾g器(尤其是開(kāi)源的GCC和LLVM)是由來(lái)自全球各地的程序員共同研發(fā)并改進(jìn)的,它們的優(yōu)化能力遠(yuǎn)遠(yuǎn)強(qiáng)于你手動(dòng)改進(jìn)代碼。 ? 也有網(wǎng)友“Shuax”使用mingw編譯,實(shí)地測(cè)試一番: ? for版本:
?
#include? 生成匯編:int main() { for(;;) { printf("for "); } }?

#include? 生成匯編:int main() { while(1) { printf("while "); } }

正方觀點(diǎn):哪有好的編譯器
不過(guò),有人跳出來(lái)反駁,現(xiàn)代編譯器的確優(yōu)化很好,二者運(yùn)行起來(lái)沒(méi)啥區(qū)別,但是實(shí)際在嵌入式工作中,尤其是MCU編程中,可沒(méi)有那么好的編譯器。 ? 一位工程師表示,很多嵌入式設(shè)備只有專用的編譯器,而過(guò)去這些編譯器,尤其是嵌入式編譯器沒(méi)做好優(yōu)化的情況下,while(1)要比f(wàn)or(;;)多幾個(gè)語(yǔ)句。 ? 因?yàn)閣hile里面是判斷啊,就會(huì)變成: ?
?
label: …… mov a, #1 jnz label? 這種情況而for(;;)的話一般只會(huì)是jmp label。 ? 許多人也有類似的經(jīng)歷,并表示,有些私有編譯器連 (int)a<<0 這種都能生成非法指令,不由地懷疑配套的破芯片到底能不能受得了各種優(yōu)化過(guò)的指令。 ?
反方觀點(diǎn):這種代碼過(guò)時(shí)了
也有工程師呼吁,不要學(xué)習(xí)這種編碼風(fēng)格,現(xiàn)在已經(jīng)是2024年了,用for(;;)表示無(wú)限循環(huán)已是一種過(guò)時(shí)的風(fēng)格了。 ? 從施特勞斯特?cái)]普博士到我國(guó)國(guó)家軍用標(biāo)準(zhǔn),均認(rèn)為 for(;;)?是一種不良風(fēng)格,可參見(jiàn): ?
GJB 8114-2013 R-1-9-4:無(wú)限循環(huán)必須使用while(1)語(yǔ)句,禁止使用for(;;)等其他形式
CppCoreGuidelines ES.73:Prefer a while-statement to a for-statement when there is no obvious loop variable
360 safe rules: for語(yǔ)句沒(méi)有明確的循環(huán)變量時(shí)應(yīng)改用while句語(yǔ)
這是為什么呢?在較為嚴(yán)格的規(guī)范體系內(nèi),for 語(yǔ)句專用于實(shí)現(xiàn)具有明確循環(huán)次數(shù)和循環(huán)變量的迭代算法,小括號(hào)內(nèi)的三個(gè)表達(dá)式應(yīng)分別專注于循環(huán)變量的初始化、循環(huán)條件的判斷、循環(huán)變量的增減,這樣可以使循環(huán)具有清晰的靜態(tài)結(jié)構(gòu),便于閱讀,利于維護(hù)。如果沒(méi)有明確的循環(huán)變量,則應(yīng)改用 while 循環(huán),避免對(duì)代碼的維護(hù)者造成誤導(dǎo)。 ? 有人說(shuō)for(;;)表示無(wú)條件循環(huán),while(1)需要作條件判斷,效率比f(wàn)or(;;)慢,有一定道理,但那都是很早以前的事情了,現(xiàn)在即使沒(méi)有編譯器優(yōu)化,這種開(kāi)銷也不會(huì)成為效率的瓶頸,是不值得優(yōu)化的,保持代碼清晰的靜態(tài)結(jié)構(gòu)更為重要! ? 類似于國(guó)軍標(biāo)這種嚴(yán)格的代碼審計(jì)規(guī)則,可參見(jiàn): github.com/Qihoo360/safe-rules ?

工程師實(shí)地測(cè)試:和編譯器和優(yōu)化有關(guān)
公眾號(hào)博主“WKJay”也在STM32F103、ARMCC5進(jìn)行過(guò)測(cè)試,將兩個(gè)邏輯分別運(yùn)行一下(不開(kāi)編譯器優(yōu)化),查看邏輯分析儀輸出的結(jié)果。 ? while(1) 邏輯運(yùn)行結(jié)果: ?

? for(;;) 邏輯運(yùn)行結(jié)果: ?

? 結(jié)果顯示,雖然循環(huán)體完全相同,但實(shí)際運(yùn)行結(jié)果來(lái)看,for(;;) 語(yǔ)句執(zhí)行得更快(45.863ms),比 while(1)(48.643ms) 快了5.7%左右。 ? 根據(jù)他的分析,for的指令更精簡(jiǎn),而while的指令相對(duì)更繁瑣,簡(jiǎn)而言之,for抄了近道,而while彎彎繞繞。 ?

? 最后,他開(kāi)啟了編譯器的O3優(yōu)化,結(jié)果,二者就幾乎不存在差別了(12.505ms): ?

? 從可讀性角度來(lái)說(shuō),while(1)簡(jiǎn)單清晰,for(;;)就模糊多了。不過(guò),對(duì)于一些比較老的專用編譯器來(lái)說(shuō),可能就需要慎重考慮使用哪種形式。 ? 對(duì)現(xiàn)代編譯器來(lái)說(shuō),二者完全就是一回事,更何況,高主頻的芯片不在乎一兩條機(jī)器指令了,所以這種情況下,怎么順眼就怎么寫(xiě)。 ?
審核編輯:黃飛
?
電子發(fā)燒友App













評(píng)論