++運算子在C/C++與C#/JAVA中的差異

來源:互聯網
上載者:User

++ 運算子

The increment operator (++) increments its operand by 1. The increment operator can appear before or after its operand
遞增運算子 (++) 將運算元加 1。遞增運算子可以出現在運算元之前或之後

The first form is a prefix increment operation. The result of the operation is the value of the operand after it has been incremented.
第一種形式是首碼增量操作。該操作的結果是運算元加 1 之後的值。

The second form is a postfix increment operation. The result of the operation is the value of the operand before it has been incremented.
第二種形式是尾碼增量操作。該運算的結果是運算元增加之前的值。

以上是MSDN對++運算子的定義。此定義在C/C++、C#、JAVA (以下簡稱它們) 中的表現形式是一致的,故i++與++i在相應語言的編譯器中的表現也是一樣的。
標題“++ 運算子在C/C++、C#、JAVA中的差異”中的差異不是語言本身的差異,而是相應編譯器的差異。

剛剛說過,i++ 與 ++i 在它們的編譯器中表現是一樣的,但i=i++; 與i=++i;呢 i=++i 這個沒有分歧,有分歧的是i=i++ 在C/C++ 中

i=i++; i 自增前的值就是這個運算式的值,在運算式執行後 i自增1 如果 i=1 的話,i=i++ 就等於1 ,i=i++ 執行後 i=2。

int i=1;  printf("%d\n",i = i++); printf("%d\n",i);   會列印出1和2 就是說會對i先賦值,然後對i自增1。

而在C#與JAVA中  i=i++ 等於 i 的值,而 i 的值會變化但仍然是之前的值。因為C#與JAVA的編譯器會嚴格遵循運算子優先順序,首先對=右側求值也就是 i 的值,

然後將 i 值入棧(將1入棧),之後優先順序的緣故 ++ 在 = 之前執行 i 先自增1 變成2,然後將棧裡的1 賦值給 i , i 這時又變回了1。

相對於C/C++的編譯器來說C#與JAVA的編譯器的做法更容易解釋也更合理,在我看產生的彙編代碼前,以為C/C++編譯器也會嚴格遵循優先順序,

故猜測是將 i 的地址入棧而不是直接將值入棧所以出現的不一致,但看過之後證明我的猜測是錯誤的,C/C++編譯器是將值放在寄存器中,

但與C#和JAVA的編譯器不同的是它未嚴格遵守運算子優先順序,就我目前掌握到的這屬於C/C++編譯器undefined的範疇,

它們的執行邏輯隨編譯器的不同而不同。所以千萬不要在C/C++程式中依賴求值順序,否則會死的很慘。

看下面一段代碼

int j, i=3; 
j=(i+3)*++i; 
printf("%d\n", i); 
printf("%d\n", j);

在知道結果前,不妨先演算一下。結果是4,28 你算對了嗎? 而在C#與JAVA中則是4,24。

相應的彙編代碼  

  int j, i=3;

   mov    DWORD PTR _i$[ebp], 3            //將3儲存到_i$[ebp]中

   j=(i+3)*++i;

   mov    eax, DWORD PTR _i$[ebp]      // 將_i$[ebp]的值放寄存器eax  
   add    eax, 1                                      // eax+1 結果放在eax中 
   mov    DWORD PTR _i$[ebp], eax      // eax的值放在_i$[ebp]中 
   mov    ecx, DWORD PTR _i$[ebp]      // 將_i$[ebp]的值放寄存器ecx 
   add    ecx, 3                                      // ecx+3 結果放在ecx中 
   imul    ecx, DWORD PTR _i$[ebp]      //  ecx*_i$[ebp] 
   mov    DWORD PTR _j$[ebp], ecx      //  將ecx的值放到_j$[ebp]中

產生的IL

[2] int32 j,[3] int32 i

int j, i=3;

  IL_000e:  ldc.i4.3         //將3入棧                                         棧中元素3 
  IL_000f:   stloc.3          //對棧頂元素做彈出操作,並儲存到相應下標的變數中      棧中無元素 

j=(i+3)*++i;

  IL_0010:  ldloc.3          //對相應下標的變數做取值操作,併入棧                  棧中元素3 
  IL_0011:  ldc.i4.3         //將3入棧                                          棧中元素3,3 
  IL_0012:  add              //對棧頂兩個元素依次做彈出並相加,結果入棧             棧中元素6 
  IL_0013:  ldloc.3          //對相應下標的變數做取值操作,併入棧                   棧中元素6,3 
  IL_0014:  ldc.i4.1         //將1入棧                                          棧中元素6,3,1 
  IL_0015:  add              //對棧頂兩個元素依次做彈出並相加,結果入棧              棧中元素6,4 
  IL_0016:  dup              //對棧頂元素做複製操作併入棧                          棧中元素6,4,4 
  IL_0017:  stloc.3          //對棧頂元素做彈出操作,並儲存到相應下標的變數中         棧中元素6,4 
  IL_0018:  mul               //對棧頂兩個元素依次做彈出並相乘,結果入棧             棧中元素24 
  IL_0019:  stloc.2          //對棧頂元素做彈出操作,並儲存到相應下標的變數中         棧中無元素

這裡沒有提供相關的JAVA位元組碼,但由於JVM和CLR都是 Stack-Based VM,所以只是具體指令不一樣,指令的運算邏輯與運算方式都是一樣的,可以參看IL部分。

我們將j=(i+3)*++i; 換成j=++i*(i+3);看看會發生什麼。相應的彙編代碼沒有任何改變,IL卻是大不相同,輸出的結果都是4,28

相關的IL 

IL_000e:  ldc.i4.3 
IL_000f:  stloc.3 
IL_0010:  ldloc.3 
IL_0011:  ldc.i4.1 
IL_0012:  add 
IL_0013:  dup 
IL_0014:  stloc.3 
IL_0015:  ldloc.3 
IL_0016:  ldc.i4.3 
IL_0017:  add 
IL_0018:  mul 
IL_0019:  stloc.2 

相信聰明的你一定可以通過之前IL的註解演算出此段IL的運算過程,我就不贅述了。

 

最後是CSDN裡某同學的問題 “int index=1;count=10;執行index=(index++) % count;後輸出結果為何還是1”

後輸出結果為何還是1 指的是輸出index還是1

相關IL

[0] int32 index,[1] int32 count

  IL_0001:  ldc.i4.1 
  IL_0002:  stloc.0 
  IL_0003:  ldc.i4.s   10 
  IL_0005:  stloc.1 
  IL_0006:  ldloc.0 
  IL_0007:  dup 
  IL_0008:  ldc.i4.1 
  IL_0009:  add 
  IL_000a:  stloc.0 
  IL_000b:  ldloc.1 
  IL_000c:  rem 
  IL_000d:  stloc.0 

相關彙編代碼   

int index=1,count=10;

    mov    DWORD PTR _index$[ebp], 1 
    mov    DWORD PTR _count$[ebp], 10        ; 0000000aH

index = (index++) % count;

    mov    eax, DWORD PTR _index$[ebp] 
    cdq 
    idiv    DWORD PTR _count$[ebp] 
    mov    DWORD PTR _index$[ebp], edx 
    mov    eax, DWORD PTR _index$[ebp] 
    add    eax, 1 
    mov    DWORD PTR _index$[ebp], eax

通過上面的IL 你能否回答他的問題呢?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.