0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

為何++i比i++執(zhí)行效率高一些呢?

Q4MP_gh_c472c21 ? 來(lái)源:嵌入式ARM ? 2019-12-03 15:37 ? 次閱讀

背景

相信很多人遇到過(guò)這樣的問(wèn)題:printf("%d,%d",i++,++i);

也糾結(jié)過(guò)這個(gè)問(wèn)題,到底答案是什么。確沒(méi)有一個(gè)參考的資料。唯一知道的是,幾乎所有C語(yǔ)言教材都這么講:i++就是先使用i的值再使i自身加一,而++i則是先使i自身加一,然后在使用i的值。出于對(duì)真理的追求。今天我們徹底弄明白此問(wèn)題。 譬如這樣的話:

int a,b;int i=10,j=10;a=i++;b=++j; 我們可以很清楚的知道a和b的值分別將是10和11。這點(diǎn)毫無(wú)疑問(wèn),因?yàn)闊o(wú)論在任何平臺(tái)任何編譯器上運(yùn)行都是這個(gè)結(jié)果!
然而對(duì)于這樣的程序:

int a,b;int i=10,j=10;a=(i++)+(i++)+(i++);b=(++j)+(++j)+(++j); 各位試想答案將是多少?
我們可以放到編譯器上運(yùn)行看一下結(jié)果如下:
先看看windows下常用的VC6結(jié)果:

恩看到了,是30和37!嗯,但..這個(gè)結(jié)果好像有點(diǎn)怪。
那再看看Linux下gcc的結(jié)果:

哦,竟然也是30 37 。
那我們?cè)倏纯垂爬弦稽c(diǎn)的TurboC的結(jié)果:


結(jié)果成了30 39 , 喔~還真有點(diǎn)怪。

當(dāng)然,就C語(yǔ)言代碼來(lái)看,i++ 和 ++i 都只有一行,看起來(lái)似乎二者的執(zhí)行效率一樣了?其實(shí)不是的,在學(xué)習(xí)C語(yǔ)言時(shí),教材和老師一般都會(huì)強(qiáng)調(diào) i++ 和 ++i 的區(qū)別,例如下面這段C語(yǔ)言代碼:

inti,j,k;i = 0;j = i++;i = 0;k = ++i;

這段C語(yǔ)言代碼執(zhí)行后,j 和 k 的值并不相等:j 等于 0,k 等于 1。既然執(zhí)行結(jié)果有差異,那么執(zhí)行效率很有可能也是有差異的,事實(shí)的確如此。查看上述C語(yǔ)言代碼對(duì)應(yīng)的匯編代碼,如下:

編譯器版本為gcc 4.8.4

可見(jiàn),j=i++; 計(jì)算機(jī)需要 4 條指令來(lái)解釋,比執(zhí)行 k=++i; 多出了一條指令。多出的一條指令為:在對(duì) i 執(zhí)行自加操作之前,先保存 i 的當(dāng)前值留作稍后使用(賦值為j)。

這是怎么回事呢?不同的編譯器結(jié)果還不一樣呢?

而且這樣看來(lái),似乎 ++i 的執(zhí)行效率比 i++ 高一些?

為何不同的編譯器結(jié)果不一樣
要說(shuō)起這其中的原因,我們要先明白兩個(gè)知識(shí)點(diǎn)。即“副作用”與“順序點(diǎn)”。 這里我們引用《C Primer Plus》的說(shuō)法:
“現(xiàn)在我們?cè)儆懻撘恍〤的術(shù)語(yǔ)。副作用(side effect)是對(duì)數(shù)據(jù)對(duì)象或文件的修改。

例如,語(yǔ)句:states = 50; 的副作用是將變量states的值設(shè)置為50。這是副作用?這看起來(lái)更像是主要目的!然而,從C的角度來(lái)看,主要目的是對(duì)表達(dá)式求值。給C一個(gè)表達(dá)式4+6,C將計(jì)算它的值為10。給C一個(gè)表達(dá)式states=50,C將計(jì)算它的值為50。計(jì)算這個(gè)表達(dá)式的副作用就是把變量states的值改變?yōu)?0。跟賦值運(yùn)算符一樣,增量運(yùn)算符和減量運(yùn)算符也有副作用,它們主要由于副作用而被使用。
一個(gè)順序點(diǎn)(sequence point)是程序執(zhí)行中的一點(diǎn);在該點(diǎn)處,所有的副作用都在進(jìn)入下一步之前被計(jì)算。在C中,語(yǔ)句里的分號(hào)標(biāo)志了一個(gè)順序點(diǎn)。它意味著在一個(gè)語(yǔ)句中賦值運(yùn)算符、增量預(yù)算符及減量運(yùn)算符所做的全部改變必須在程序進(jìn)入下一個(gè)語(yǔ)句前發(fā)生。任何一個(gè)完整的表達(dá)式的結(jié)束也是一個(gè)順序點(diǎn)。
什么是完整的表達(dá)式呢?一個(gè)完整的表達(dá)式(full expression)是這樣一個(gè)表達(dá)式—-它不是一個(gè)更大的表達(dá)式的子表達(dá)式。完整的表達(dá)式的例子包括一個(gè)表達(dá)式語(yǔ)句里的表達(dá)式和在一個(gè)while循環(huán)里作為判斷條件的表達(dá)式。
順序點(diǎn)幫助闡明后綴增量動(dòng)動(dòng)作何時(shí)發(fā)生。例如,考慮下面的代碼:

while(guests++<10)printf(“%d ”,guests);? 有時(shí)C的初學(xué)者會(huì)設(shè)想在本程序中“先使用該值,然后增加它的值”的意思是在使用printf()語(yǔ)句后在增加guests的值。然而,因?yàn)間uests++<10是while循環(huán)的判斷條件,所以它是一個(gè)完整的表達(dá)式,這個(gè)表達(dá)式的結(jié)束就是一個(gè)順序點(diǎn)。因此,C保證副作用(增加guests的值)在程序進(jìn)入printf()前發(fā)生。同時(shí)使用后綴形式保證了guests在于10比較后才增加。
現(xiàn)在考慮這個(gè)語(yǔ)句:

Y=(4+ x++)+(6+ x++);
表達(dá)式4+x++不是一個(gè)完整的表達(dá)式,所以C不能保證在計(jì)算子表達(dá)式4+x++后立即增加x。這里,完整表達(dá)式是整個(gè)賦值語(yǔ)句,并且分號(hào)標(biāo)記了順序點(diǎn),所以C能保證的是在程序進(jìn)入后續(xù)語(yǔ)句前x將增加兩次。C 沒(méi)有指明x是在每個(gè)子表達(dá)式被計(jì)算后增加還是在整個(gè)表達(dá)式被計(jì)算后增加,這就是我們要避免使用這類語(yǔ)句的原因。 這是《C Primer Plus》的說(shuō)法,相信您應(yīng)該有一定答案了。
沒(méi)錯(cuò),那就是對(duì)于i=10;(++i)+(++i)+(++i);這樣的語(yǔ)句。C語(yǔ)言標(biāo)準(zhǔn)并沒(méi)有作規(guī)定。有的編譯器計(jì)算出來(lái)是39,因?yàn)闀?huì)使i的值自增三次變?yōu)?3,然后使用增加三次之后也就是13的3個(gè)值相加為39。而有的編譯器計(jì)算結(jié)果則為37,如VisaulC++6.0則會(huì)先計(jì)算前兩個(gè)i的值為12,第三個(gè)i的值變成了加三次以后的值為13,因此結(jié)果是12+12+13=37。如果有心的話,您可以分別在VC6和TC上本別測(cè)試;(++i)+(++i)+(++i) +(++i)的值來(lái)洞悉不同編譯器的處理規(guī)則。

那么,回到最初的printf的問(wèn)題,明白求值的順序之后,再來(lái)看printf的求值問(wèn)題,printf的參數(shù)都是從左到右依次壓入棧內(nèi),所以計(jì)算起來(lái)求值運(yùn)算的時(shí)候則是由右至左(棧的特點(diǎn):即先進(jìn)后出),那么至此,想必您已經(jīng)完全想明白了這類問(wèn)題的全部了!
所以講到這里,想必大家就清楚緣由了,不同編譯器的處理過(guò)程是不同的。所以并沒(méi)有唯一的標(biāo)準(zhǔn)答案!現(xiàn)在大家明白了嗎?

為何++i比i++執(zhí)行效率高一些呢?

那為了寫(xiě)出效率更高的C語(yǔ)言程序,以后是不是應(yīng)該盡量使用 ++i,而不是 i++ 了呢?例如下面這樣的C語(yǔ)言代碼:

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

是不是上面那行C語(yǔ)言代碼的執(zhí)行效率低于下面的呢?只能說(shuō)理論如此,實(shí)際上,現(xiàn)代C語(yǔ)言編譯器已經(jīng)足夠聰明,它會(huì)根據(jù)上下文編譯C語(yǔ)言代碼。

應(yīng)該明白,i++ 和 ++i 的效率差異主要來(lái)自于處理 i++ 時(shí),需要先保存 i 的當(dāng)前值留作稍后使用。如果之后沒(méi)有人使用 i 的當(dāng)前值,也就是說(shuō)沒(méi)有C語(yǔ)言代碼讀取 i++ 的值,編譯器實(shí)在沒(méi)有必要保存 i 的當(dāng)前值了,因此就會(huì)將這一步優(yōu)化掉。

為了便于分析,我們編寫(xiě)下面這樣的C語(yǔ)言代碼:

int i = 0;i++;++i;

與上面的例子相比,區(qū)別在于在執(zhí)行 i++ 時(shí),沒(méi)有人關(guān)心 i 的當(dāng)前值了。查看這段C語(yǔ)言代碼對(duì)應(yīng)的匯編代碼:

顯然,i++ 和 ++i 對(duì)應(yīng)的指令是一模一樣的,不再有執(zhí)行效率上的差異。

C語(yǔ)言中的 i++ 和 ++i 是有區(qū)別的,這就有可能帶來(lái)效率上的差異。如果有代碼關(guān)心 i++ 執(zhí)行時(shí)的 i 當(dāng)前值,程序在對(duì) i 進(jìn)行自加操作時(shí),將不得不先保存 i 的當(dāng)前值,而 ++i 就無(wú)需保存當(dāng)前值,這就會(huì)帶來(lái)效率上的差異。如果沒(méi)人關(guān)心 i++ 的當(dāng)前值,那么現(xiàn)代大多數(shù)C語(yǔ)言編譯器將會(huì)將這一差異優(yōu)化掉,此時(shí) i++ 和 ++i 不再有效率上的差異。

-END-

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11329

    瀏覽量

    209970
  • C語(yǔ)言
    +關(guān)注

    關(guān)注

    180

    文章

    7614

    瀏覽量

    137257

原文標(biāo)題:C語(yǔ)言靈魂拷問(wèn):++i為何比i++執(zhí)行效率高!有何區(qū)別?

文章出處:【微信號(hào):gh_c472c2199c88,微信公眾號(hào):嵌入式微處理器】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    為何基本碳化硅MOSFET在充電樁電源單級(jí)拓?fù)鋵?shí)測(cè)效率高于進(jìn)口器件

    基本碳化硅MOSFET在充電樁電源單級(jí)拓?fù)鋵?shí)測(cè)效率高于進(jìn)口器件
    的頭像 發(fā)表于 01-13 09:58 ?125次閱讀
    <b class='flag-5'>為何</b>基本碳化硅MOSFET在充電樁電源單級(jí)拓?fù)鋵?shí)測(cè)<b class='flag-5'>效率高</b>于進(jìn)口器件

    天合光能重磅發(fā)布i-TOPCon Ultra技術(shù)

    實(shí)驗(yàn)室效率高達(dá)26.58%,首次將TOPCon電池效率推升到26.5%,應(yīng)用i-TOPCon Ultra技術(shù)后,天合光能至尊N型組
    的頭像 發(fā)表于 11-23 14:47 ?541次閱讀

    為什么下雨天手機(jī)信號(hào)平時(shí)差一些

    下雨我們總會(huì)覺(jué)得手機(jī)信號(hào)平時(shí)差一些,這到底是什么原因?今天讓我們來(lái)探究竟。 ? 我們知道手機(jī)信號(hào)是以特高頻電磁波的形式在空氣中傳播的
    的頭像 發(fā)表于 11-21 13:51 ?577次閱讀

    如何設(shè)計(jì)散熱效率高的集成BLDCM電機(jī)驅(qū)動(dòng)PCB

    電子發(fā)燒友網(wǎng)站提供《如何設(shè)計(jì)散熱效率高的集成BLDCM電機(jī)驅(qū)動(dòng)PCB.pdf》資料免費(fèi)下載
    發(fā)表于 09-29 09:59 ?0次下載
    如何設(shè)計(jì)散熱<b class='flag-5'>效率高</b>的集成BLDCM電機(jī)驅(qū)動(dòng)PCB

    物聯(lián)網(wǎng)中常見(jiàn)的I/O擴(kuò)展電路設(shè)計(jì)方案_IIC I/O擴(kuò)展芯片

    )自帶的I/O端口數(shù)量有限,但物聯(lián)網(wǎng)項(xiàng)目往往需要連接大量的傳感器、執(zhí)行器和其他外設(shè)。I2C I/O擴(kuò)展芯片能夠通過(guò)I2C接口提供額外的
    的頭像 發(fā)表于 09-24 11:29 ?591次閱讀
    物聯(lián)網(wǎng)中常見(jiàn)的<b class='flag-5'>I</b>/O擴(kuò)展電路設(shè)計(jì)方案_IIC <b class='flag-5'>I</b>/O擴(kuò)展芯片

    精確測(cè)量超低I器件的效率

    電子發(fā)燒友網(wǎng)站提供《精確測(cè)量超低I器件的效率.pdf》資料免費(fèi)下載
    發(fā)表于 09-04 10:09 ?0次下載
    精確測(cè)量超低<b class='flag-5'>I</b>器件的<b class='flag-5'>效率</b>

    振動(dòng)電機(jī)普通電機(jī)效率高

    振動(dòng)電機(jī)和普通電機(jī)是兩種不同類型的電機(jī),它們?cè)诮Y(jié)構(gòu)、工作原理、應(yīng)用領(lǐng)域等方面都存在差異。因此,不能簡(jiǎn)單地說(shuō)振動(dòng)電機(jī)普通電機(jī)效率高或低,需要根據(jù)具體的應(yīng)用場(chǎng)景和需求來(lái)判斷。 本文將從以下幾個(gè)方面
    的頭像 發(fā)表于 06-12 16:00 ?1145次閱讀

    I2C主機(jī)產(chǎn)生不了起始位的原因?

    I2C主機(jī)程序使用的是官方例程,但是執(zhí)行I2C_GenerateSTART(ENABLE)這步后,SBMSLBUSY位置位,START位為0,并且SCL管腳會(huì)由3.3V降到100m
    發(fā)表于 05-13 07:56

    為何什么risc-v芯片arm的效率高

    RISC-V芯片在某些情況下可能相對(duì)于ARM架構(gòu)芯片表現(xiàn)出更高的效率,這主要得益于RISC-V設(shè)計(jì)的一些特點(diǎn)和優(yōu)勢(shì)。 首先,RISC-V指令集架構(gòu)是模塊化的,這意味著設(shè)計(jì)師可以根據(jù)特定應(yīng)用的需求
    發(fā)表于 04-28 09:38

    STM8S程序每次執(zhí)行到for循環(huán),只能執(zhí)行次,走到i++時(shí),程序跑飛,是怎么回事?

    ]; } rece_flag=0; GPIOD->ODR=~GPIO_PIN_7;//receive } } 程序每次執(zhí)行到for循環(huán),只能執(zhí)行次,走到i++時(shí),程序
    發(fā)表于 04-28 08:10

    鴻蒙原生應(yīng)用開(kāi)發(fā)-ArkTS語(yǔ)言基礎(chǔ)類庫(kù)多線程I/O密集型任務(wù)開(kāi)發(fā)

    使用異步并發(fā)可以解決單次I/O任務(wù)阻塞的問(wèn)題,但是如果遇到I/O密集型任務(wù),同樣會(huì)阻塞線程中其它任務(wù)的執(zhí)行,這時(shí)需要使用多線程并發(fā)能力來(lái)進(jìn)行解決。 I/O密集型任務(wù)的性能重點(diǎn)通常不在于
    發(fā)表于 03-21 14:57

    AS-i 通訊協(xié)議是什么? AS-i 協(xié)議的特點(diǎn)

    AS-i通信協(xié)議是種用于傳感器和執(zhí)行器之間通信的總線標(biāo)準(zhǔn),屬于種開(kāi)放的標(biāo)準(zhǔn)。它是種高效且功能強(qiáng)大的總線系統(tǒng),可將最低現(xiàn)場(chǎng)層的所有傳感器
    的頭像 發(fā)表于 03-20 15:50 ?1522次閱讀

    FANUC外部I/O點(diǎn)數(shù)不夠用了怎么辦?可以擴(kuò)展I/O點(diǎn)數(shù)嗎?

    FANUC外部I/O點(diǎn)數(shù)不夠用了怎么辦?可以擴(kuò)展I/O點(diǎn)數(shù)嗎? 擴(kuò)展FANUC的外部I/O點(diǎn)數(shù)是種常見(jiàn)的需求,這可以通過(guò)一些方法來(lái)實(shí)現(xiàn)。
    的頭像 發(fā)表于 02-18 15:21 ?2015次閱讀

    電腦系統(tǒng)i5和i7有什么區(qū)別

    i5和i7是英特爾公司推出的兩款處理器系列,是目前市場(chǎng)上較為流行和廣泛應(yīng)用的處理器之。雖然它們都屬于同家公司的產(chǎn)品,但在性能、核心數(shù)、價(jià)格等方面存在
    的頭像 發(fā)表于 02-02 14:45 ?4972次閱讀

    PSOC Creator 4.4中是否有一些設(shè)置可以阻止strtok操作?

    我需要一些幫助才能開(kāi)始使用這個(gè)功能。 我做了個(gè)簡(jiǎn)單的代碼,意圖用逗號(hào)作為分隔符來(lái)標(biāo)記字符串。 我嘗試在 PC 上模擬以下代碼并將其改編為 PSoc5LP: [i]int 主要 () [i
    發(fā)表于 01-24 08:31