91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

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

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

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

C/C++靈魂拷問:++i與i++哪個執(zhí)行效率高?有什么區(qū)別?

Q4MP_gh_c472c21 ? 來源:高效程序員 ? 作者:高效程序員 ? 2022-03-31 14:04 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

背景:相信很多人都遇到過這樣的問題:printf("%d,%d",i++,++i); 也糾結(jié)過這個問題,到底答案是什么,都沒有一個參考的資料……而唯一知道的是,幾乎所有C語言教材都這么講:i++就是先使用i的值再使i自身加一,而++i則是先使i自身加一,然后在使用i的值。 出于對真理的追求,今天我們就徹底弄明白此問題! 譬如這樣的話:
int a,b;int i=10,j=10;a=i++;b=++j;

我們可以很清楚的知道a和b的值分別將是10和11。這點毫無疑問,因為無論在任何平臺任何編譯器上運行都是這個結(jié)果!

然而,對于這樣的程序:

int a,b;int i=10,j=10;a=(i++)+(i++)+(i++);b=(++j)+(++j)+(++j);

各位試想答案將是多少?我們可以放到編譯器上,運行看一下結(jié)果。

先來看看windows下常用的VC6結(jié)果:

3500f10a-b0b2-11ec-aa7f-dac502259ad0.jpg

嗯,看到了,是30和37。但這個結(jié)果好像有點怪…… 那就再看看Linux下gcc的結(jié)果:

3515d1f6-b0b2-11ec-aa7f-dac502259ad0.png

哦,竟然也是30和37!
那么,我們再看看古老一點的TurboC的結(jié)果:

352cd126-b0b2-11ec-aa7f-dac502259ad0.jpg

354074e2-b0b2-11ec-aa7f-dac502259ad0.jpg

結(jié)果成了30和39,還真有點怪。 當然,就C語言代碼來看,i++和++i都只有一行,看起來似乎二者的執(zhí)行效率一樣了?其實不是的,在學習C語言時,教材和老師一般都會強調(diào)i++和++i的區(qū)別,例如下面這段C語言代碼:
inti,j,k;i = 0;j = i++;i = 0;k = ++i;
這段C語言代碼執(zhí)行后,j和k的值并不相等:j等于0,k等于1。 既然執(zhí)行結(jié)果有差異,那么執(zhí)行效率很有可能也是有差異的,事實的確如此。 查看上述C語言代碼對應的匯編代碼,如下:

3553f83c-b0b2-11ec-aa7f-dac502259ad0.jpg

編譯器版本為gcc 4.8.4

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

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

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

為什么不同的編譯器結(jié)果不一樣?
要說起這其中的原因,我們要先明白兩個知識點,即“副作用”與“順序點”。 這里我們引用《C Primer Plus》的說法:“現(xiàn)在我們再討論一些C的術(shù)語。副作用(side effect)是對數(shù)據(jù)對象或文件的修改?!?/span>
例如語句states=50,它的副作用是將變量states的值設置為50。這是副作用?這看起來更像是主要目的!然而,從C的角度來看,主要目的是對表達式求值。給C一個表達式4+6,C將計算它的值為10。給C一個表達式states=50,C將計算它的值為50。計算這個表達式的副作用就是把變量states的值改變?yōu)?0。跟賦值運算符一樣,增量運算符和減量運算符也有副作用,它們主要由于副作用而被使用。
一個順序點(sequence point)是程序執(zhí)行中的一點;在該點處,所有的副作用都在進入下一步之前被計算。在C中,語句里的分號標志了一個順序點。它意味著在一個語句中賦值運算符、增量預算符及減量運算符所做的全部改變必須在程序進入下一個語句前發(fā)生。任何一個完整的表達式的結(jié)束也是一個順序點。
什么是完整的表達式呢?一個完整的表達式(full expression)是這樣一個表達式—-它不是一個更大的表達式的子表達式。完整的表達式的例子包括一個表達式語句里的表達式和在一個while循環(huán)里作為判斷條件的表達式。
順序點幫助闡明后綴增量動動作何時發(fā)生,比如考慮下面的代碼:
while(guests++<10)printf(“%d
”,guests);

有時C的初學者會設想在本程序中“先使用該值,然后增加它的值”的意思是在使用printf()語句后在增加guests的值。然而,因為guests++<10是while循環(huán)的判斷條件,所以它是一個完整的表達式,這個表達式的結(jié)束就是一個順序點。

因此,C保證副作用(增加guests的值)在程序進入printf()前發(fā)生。同時使用后綴形式保證了guests在于10比較后才增加。


現(xiàn)在考慮這個語句:

Y=(4+ x++)+(6+ x++);

表達式4+x++不是一個完整的表達式,所以C不能保證在計算子表達式4+x++后立即增加x。這里完整表達式是整個賦值語句,并且分號標記了順序點,所以C能保證的是在程序進入后續(xù)語句前x將增加兩次。C沒有指明x是在每個子表達式被計算后增加還是在整個表達式被計算后增加,這就是我們要避免使用這類語句的原因。

這是《C Primer Plus》的說法,相信您應該有一定答案了。


沒錯,那就是對于i=10;(++i)+(++i)+(++i);這樣的語句。C語言標準并沒有作規(guī)定。有的編譯器計算出來是39,因為會使i的值自增三次變?yōu)?3,然后使用增加三次之后,也就是13的3個值相加為39。而有的編譯器計算結(jié)果則為37,如VisaulC++6.0則會先計算前兩個i的值為12,第三個i的值變成了加三次以后的值為13,因此結(jié)果是12+12+13=37。

如果有心的話,您可以分別在VC6和TC上本別測試;(++i)+(++i)+(++i)+(++i)的值來洞悉不同編譯器的處理規(guī)則。

那么,回到最初的printf的問題,明白求值的順序之后,再來看printf的求值問題,printf的參數(shù)都是從左到右依次壓入棧內(nèi),所以計算起來求值運算的時候則是由右至左(棧的特點:即先進后出)。那么至此,想必您已經(jīng)完全想明白了這類問題的全部了!

所以講到這里,想必大家就清楚緣由了,不同編譯器的處理過程是不同的。所以并沒有唯一的標準答案!現(xiàn)在大家明白了嗎?

為什么++i比i++執(zhí)行效率高一些呢? 為了寫出效率更高的C語言程序,以后是不是應該盡量使用++i,而不是i++了呢?例如下面這樣的C語言代碼:
for(i=0; i<10; i++);for(i=0; i<10; ++i);
是不是上面那行C語言代碼的執(zhí)行效率低于下面的呢?只能說理論如此,實際上,現(xiàn)代C語言編譯器已經(jīng)足夠聰明,它會根據(jù)上下文編譯C語言代碼。 應該明白,i++和++i的效率差異主要來自于處理i++時,需要先保存i的當前值留作稍后使用。如果之后沒有人使用i的當前值,也就是說沒有C語言代碼讀取i++的值,編譯器實在沒有必要保存i的當前值了,因此就會將這一步優(yōu)化掉。 為了便于分析,我們編寫下面這樣的C語言代碼:
int i = 0;i++;++i;
與上面的例子相比,區(qū)別在于在執(zhí)行i++時,沒有人關(guān)心i的當前值了。查看這段C語言代碼對應的匯編代碼:

3567966c-b0b2-11ec-aa7f-dac502259ad0.png

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

審核編輯 :李倩

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

    關(guān)注

    183

    文章

    7644

    瀏覽量

    145579
  • C++
    C++
    +關(guān)注

    關(guān)注

    22

    文章

    2124

    瀏覽量

    77112
  • 編譯器
    +關(guān)注

    關(guān)注

    1

    文章

    1672

    瀏覽量

    51599

原文標題:C/C++靈魂拷問:++i與i++哪個執(zhí)行效率高?有什么區(qū)別?

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    RA MCU眾測寶典 | I2C讀取EEPROM

    I2C協(xié)議讀取EEPROM數(shù)據(jù)。瑞薩嵌入式小百科將帶著大家從I2C總線原理、EEPROM(AT24C02)特性,到FSP中I2C的引腳配置、參數(shù)設置,再到字節(jié)寫、
    的頭像 發(fā)表于 01-13 18:05 ?6748次閱讀
    RA MCU眾測寶典 | <b class='flag-5'>I</b>2<b class='flag-5'>C</b>讀取EEPROM

    NXP NTAG I2C plus:開啟NFC應用新境界

    NXP NTAG I2C plus:開啟NFC應用新境界 在當今的電子世界中,NFC(近場通信)技術(shù)正以其便捷、高效的特點,廣泛應用于各個領(lǐng)域。NXP推出的NTAG I2C plus系
    的頭像 發(fā)表于 12-30 17:10 ?604次閱讀

    PCA9539:16位I2C與SMBus低功耗I/O擴展器深度解析

    2.3 - 5.5V $V_{CC}$ 工作環(huán)境設計,可通過I2C接口為大多數(shù)微控制器家族提供通用遠程I/O擴展功能。它具備低功耗、
    的頭像 發(fā)表于 12-29 09:55 ?281次閱讀

    P82B715:I2C總線擴展的得力助手

    )的P82B715,一款專門用于緩沖電容I2C總線系統(tǒng)的器件,看看它是如何解決這些問題的。 文件下載: p82b715.pdf 1. 器件概述 P82B715是一款支持通過I2C總線
    的頭像 發(fā)表于 12-26 10:20 ?694次閱讀

    基于FPGA的I2C控制模塊設計

    I2C_WRITE_WDATA.v模塊實現(xiàn)I2C寫時序,I2C_Controller (I2C控制器)例化了I2C_WRITE_WDATA.
    的頭像 發(fā)表于 12-26 09:48 ?4905次閱讀
    基于FPGA的<b class='flag-5'>I2C</b>控制模塊設計

    C語言與C++區(qū)別及聯(lián)系

    缺點:性能比面向過程低。 二、具體語言上的區(qū)別 1、關(guān)鍵字的不同 C語言32個關(guān)鍵字;C++63個關(guān)鍵字。 2、后綴名不同
    發(fā)表于 12-24 07:23

    TCA9617A:I2C總線應用的理想之選

    TCA9617A:I2C總線應用的理想之選 在電子工程師的日常設計中,I2C總線系統(tǒng)的設計和優(yōu)化是一個常見的挑戰(zhàn)。今天,我們就來深入探討一款在I
    的頭像 發(fā)表于 12-23 11:10 ?317次閱讀

    C語言和C++之間的區(qū)別是什么

    區(qū)別 1、面向?qū)ο缶幊?(OOP): C語言是一種面向過程的語言,它強調(diào)的是通過函數(shù)將任務分解為一系列步驟進行執(zhí)行。 C++C語言的基礎(chǔ)
    發(fā)表于 12-11 06:23

    ?CAT24C64 64Kb I2C CMOS串行EEPROM技術(shù)深度解析

    安森美 (onsemi) CAT24C64 64Kb I^2^C CMOS串行EEPROM在內(nèi)部為每個8位安排8192個字。這些EEPROM具有32字節(jié)頁面寫入緩沖區(qū),并支持標準(1
    的頭像 發(fā)表于 11-25 10:14 ?572次閱讀
    ?CAT24<b class='flag-5'>C</b>64 64Kb <b class='flag-5'>I</b>2<b class='flag-5'>C</b> CMOS串行EEPROM技術(shù)深度解析

    TCA9536 4位I2C/SMBus I/O擴展器技術(shù)解析

    Texas Instruments TCA9536 4位I/O擴展器用于I^2^C總線,可在1.65V至 5.5V的V~CC~ 下運行。它可通過I^2^
    的頭像 發(fā)表于 09-19 14:45 ?805次閱讀
    TCA9536 4位<b class='flag-5'>I2C</b>/SMBus <b class='flag-5'>I</b>/O擴展器技術(shù)解析

    深入剖析I2C協(xié)議

    I2C是由Philips開發(fā)的簡單的雙向兩線總線,在深入淺出理解SPI協(xié)議中,我們區(qū)分了單工,半雙工,全雙工協(xié)議數(shù)據(jù)流向的區(qū)別,根據(jù)特征,I2C協(xié)議屬于半雙工協(xié)議(即同一時刻,數(shù)據(jù)單向流動)。此外
    的頭像 發(fā)表于 08-21 15:10 ?3665次閱讀
    深入剖析<b class='flag-5'>I2C</b>協(xié)議

    TCAL9539 I2C總線I/O擴展器技術(shù)解析與應用指南

    Texas Instrument TCAL9539/TCAL9539-Q1 I^2^C總線/SMBus I/O擴展器為雙線雙向I^2^C總線
    的頭像 發(fā)表于 08-08 11:49 ?1344次閱讀
    TCAL9539 <b class='flag-5'>I2C</b>總線<b class='flag-5'>I</b>/O擴展器技術(shù)解析與應用指南

    效率、6通道、白光LED驅(qū)動器,帶I2C接口 skyworksinc

    電子發(fā)燒友網(wǎng)為你提供()高效率、6通道、白光LED驅(qū)動器,帶I2C接口相關(guān)產(chǎn)品參數(shù)、數(shù)據(jù)手冊,更有高效率、6通道、白光LED驅(qū)動器,帶I2C接口的引腳圖、接線圖、封裝手冊、中文資料、英
    發(fā)表于 07-30 18:31
    高<b class='flag-5'>效率</b>、6通道、白光LED驅(qū)動器,帶<b class='flag-5'>I2C</b>接口 skyworksinc

    CY7C65214和CY7C65211/3/5什么區(qū)別?

    CY7C65214 和其他 USB 串行橋接控制器之間什么區(qū)別:CY7C65211、CY7C65213 和 CY7
    發(fā)表于 05-29 06:49

    I2C總線復用

    帝晶智慧屏I2C總線復用
    的頭像 發(fā)表于 03-11 17:20 ?2081次閱讀