程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> 【轉】 C語言自增自減運算符深入剖析,運算符深入剖析

【轉】 C語言自增自減運算符深入剖析,運算符深入剖析

編輯:關於C語言

【轉】 C語言自增自減運算符深入剖析,運算符深入剖析


轉自:http://bbs.csdn.net/topics/330189207

C語言的自增++,自減--運算符對於初學者來說一直都是個難題,甚至很多老手也會產生困惑,最近我在網上看到一個問題:
#include <stdio.h> 
void main()  /*主函數*/ 
{
 int a,b,c,d; 
 a=5;
 b=5; 
 c=(a++)+(a++)+(a++); 
 d=(++b)+(++b)+(++b); 
 printf("a=%d,b=%d,c=%d,d=%d\n",a,b,c,d); 

結果是什麼?

而後Eric搜了一下後發現,類似的問題很多,也就是說對自增自減運算符感到迷惑是一個普遍存在的問題,基於此,Eric決定對自增自減運算符做個小小的解析,希望能給C語言愛好者們提供參考,解決對此問題的困惑。

自增自減運算符語法

自增運算符 ++ 使操作數的值加1,其操作數必須為可變左值(可簡單地理解為變量)。對於自增就是加1這一點,Eric想大家都不會有什麼疑問。

問題在於:++ 可以置於操作數前面,也可以放在後面,如:

  ++i;
  i++ ;
++i表示,i自增1後再參與其它運算;而i++ 則是i參與運算後,i的值再自增1。

自減運算符--與之類似,只不過是變加為減而已,故不重述。

實例剖析

下面我們通過一些實例來深入理解自增運算符的特性,自減運算符同理自悟

例一:

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

對此,Eric想大家都不會有什麼困惑,結果就是 4,5;下面我們來做一點小改動:

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

結果又是多少呢?這裡就開始體現出++前置與後置的區別了,結果是3,5。結合此例,我們回頭再來理解一下“++前置:i自增1後再參與其它運算;++後置:i參與運算後,i的值再自增1”。很明顯,a = i++;由於是先執行賦值運算,再自增,所以結果是a=3,i=4;而b = ++j;
則因先自增,然後再賦值,所以b,j均為5。

其實基本道理就這麼簡單了,但在更復雜點的情況下又會如何呢,請看:

例二:

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

問題又來了,i++ + i++是先自增一次,相加,再自增,然後賦值呢,還是先相加賦值然後自增兩次呢。另外,++j又將如何表現呢?

結果是:6,12

這下明白了,原來 i++的理解應該是執行完整個表達式的其他操作後,然後才自增,所以例子中的a=3+3=6;而後i再自增2次,i=5;相反,++j是先自增然後再參加其它運算,所以b=6+6=12。

到此,是否就徹底明了了呢?然後回到引子中的問題:

例三:

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

有人可能會說,這很簡單,我全明白了:a=3+3+3=9,i=6,b=5+5+5=15,j=5。真的是這樣嗎?

結果卻是:9,19

這下可好,又糊塗了。對於a = i++ + i++ + i++;我們已經沒有疑問了,++後置就是執行完整個表達式的其他操作後,然後才自增,上例中也得到了驗證,但 b = ++j + ++j + ++j;又該如何理解呢?

原理表達式中除了預算法本身的優先級外,還有一個結合性問題。在++j + ++j + ++j;中,因為存在兩個同級的+運算,根據+運算符的左結合性,在編譯時,其實是先處理前面的(++j + ++j)這部分,然後再將此結果再和++j相加。具體過程參見匯編代碼:

int b = ++j + ++j + ++j;
0040B7DD   mov         ecx,dword ptr [ebp-8]
0040B7E0   add         ecx,1
0040B7E3   mov         dword ptr [ebp-8],ecx  // 第一個++j
0040B7E6   mov         edx,dword ptr [ebp-8]
0040B7E9   add         edx,1
0040B7EC   mov         dword ptr [ebp-8],edx  // 第二個++j
0040B7EF   mov         eax,dword ptr [ebp-8]
0040B7F2   add         eax,dword ptr [ebp-8]  // ++j + ++j 
0040B7F5   mov         ecx,dword ptr [ebp-8]
0040B7F8   add         ecx,1
0040B7FB   mov         dword ptr [ebp-8],ecx  // 第三個++j
0040B7FE   add         eax,dword ptr [ebp-8]  // ++j + ++j + ++j
0040B801   mov         dword ptr [ebp-10h],eax  // 賦值給b

另外我們看看a = i++ + i++ + i++;的匯編代碼:

int a = i++ + i++ + i++;
0040B7B6   mov         eax,dword ptr [ebp-4]
0040B7B9   add         eax,dword ptr [ebp-4]    // i+i
0040B7BC   add         eax,dword ptr [ebp-4]   // i+i+i
0040B7BF   mov         dword ptr [ebp-0Ch],eax // 賦值給a
0040B7C2   mov         ecx,dword ptr [ebp-4]
0040B7C5   add         ecx,1
0040B7C8   mov         dword ptr [ebp-4],ecx  // 第一次i++
0040B7CB   mov         edx,dword ptr [ebp-4]
0040B7CE   add         edx,1
0040B7D1   mov         dword ptr [ebp-4],edx  // 第二次i++
0040B7D4   mov         eax,dword ptr [ebp-4]
0040B7D7   add         eax,1
0040B7DA   mov         dword ptr [ebp-4],eax  // 第三次i++

果然不出所料。到此,++運算符前置後置的問題應該徹底解決了。

為了驗證一下上述結論,我們再看:

例四:

  int i=1;
  int j=1;
  int a = i++ + i++ + i++ + i++ + i++ + i++ + i++; // 七個
  int b = ++j + ++j + ++j + ++j + ++j + ++j + ++j;
  printf("%d, %d\n", a, b);
  printf("%d, %d\n", i, j);

規則就是規則,咱的計算機可不是黑客帝國的母體,總是要遵循它的

a = 1+1+1+1+1+1+1 = 7,  i=8
b = 3+3+4+5+6+7+8 = 36,  j=8

一切OK,恭喜你還生活在21世紀的地球,不用擔心matrix控制你的思維和生活

注:以上結果及解釋出自VC編譯器,但對於++這個問題是和編譯器的解析有關的,不同廠家可能理解不一致,因手頭沒有其他開發環境,暫無法做全面分析,本文只是為了說明++,--這運算符的一些特性,尤其是前置後置的區別這個問題。類似的問題如果有困惑,最好是寫程序做試驗解決,請勿生搬硬套。謝謝!在實際的編程實踐中,類似的問題除了要試驗搞清外,Eric認為應該盡量避免引入環境相關的編程技巧。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved