zerglurker的C語言教程009——運算子詳解(一)

來源:互聯網
上載者:User

標籤:c++   c語言   編程   語言   教程   

在之前幾節我們講過資料類型、講過函數、講過代碼執行順序以及一些添加簡單函數的方法。

這一節我們將著重講講運算子。包括運算子的含義以及優先順序的概念

在C語言中,以下運算子是被公認的:

C/C++語言運算子詳解
優先順序 運算子 名稱以及含義 運算目 使用樣本 結合方向 可否重載 附加說明
() 圓括弧 單目 (運算式) 括弧內的表達永遠先計算
dynamic_cast<>() 類型動態轉化 單目 dynamic_cast<目標類型>(源) C++專有,不能轉換返回空
static_cast<>() 類型靜態轉化 單目 static_cast<目標類型>(源) C++專有,不檢測轉換【注1】
reinterpret_cast<>() 類型解讀轉化 單目 reinterpret_cast<目標類型>(源) C++專有,強制轉換【注1】
const_cast<>() 去常量轉化 單目 const_cast<目標類型>(源) C++專有,可將常量轉非常量
0 :: 範圍解析 雙目 網域名稱::目標名 從左向右 C++專有
1 [] 下標運算子 雙目 數組名[運算式] 從左向右 兩種語言都有
1 () 函數調用 雙目 函數名(參數) 從左向右 兩種語言都有
1 . 對象成員選擇 雙目 對象.成員 從左向右 兩種語言都有
1 -> 指標成員選擇 雙目 對象指標->成員 從左向右 兩種語言都有
1 {} 組合運算 未知 {語句1;語句2;…語句n;} 從左向右 兩種語言都有
2 ++ 自增運算 單目 變數++
++變數【注2】
從左向右
從右向左
兩種語言都有
2 -- 自減運算 單目 變數--
--變數【注2】
從左向右
從右向左
兩種語言都有
2 + 正號 單目 +變數 從右向左 兩種語言都有
2 - 負號 單目 -變數 從右向左 兩種語言都有
2 ! 邏輯非 單目 !運算式 從右向左 兩種語言都有
2 ~ 按位取反 單目 ~變數 從右向左 兩種語言都有
2 * 指標解引用 單目 *指標 從右向左 兩種語言都有
2 & 取地址 單目 &變數 從右向左 兩種語言都有
2 (類型) 強制類型轉換 單目 (類型)源 從右向左 兩種語言都有
2 sizeof 擷取變數佔用
空間大小記憶體
單目 sizeof(源) 從右向左 兩種語言都有
2 new/new[] 分配記憶體 單目 new 類型名 或 new[]類型名 從右向左 C++專有
2 delete/delete[] 釋放記憶體 單目 delete 指標 或者 delete[]指標 從右向左 C++專有
3 .* 成員對象選擇 雙目 對象.*成員名 或
對象.*成員指標
從左至右 C++專有
3 ->* 成員指標選擇 雙目 對象指標->*成員名 或
對象指標->.*成員指標
從左至右 C++專有
4 * 乘法 雙目 變數1*變數2 從左至右 兩種語言都有
4 / 除法 雙目 變數1/變數2 從左至右 兩種語言都有
4 % 取餘 雙目 變數1%變數2 從左至右 兩種語言都有
5 + 加法 雙目 變數1+變數2 從左至右 兩種語言都有
5 - 減法 雙目 變數1-變數2 從左至右 兩種語言都有
6 << 按位左移 雙目 變數1<<變數2 從左至右 兩種語言都有
6 >> 按位右移 雙目 變數1>>變數2 從左至右 兩種語言都有
7 < 小於 雙目 變數1<變數2 從左至右 兩種語言都有
7 <= 不大於 雙目 變數1<=變數2 從左至右 兩種語言都有
7 > 大於 雙目 變數1>變數2 從左至右 兩種語言都有
7 >= 不小於 雙目 變數1>=變數2 從左至右 兩種語言都有
8 == 邏輯等 雙目 變數1==變數2 從左至右 兩種語言都有
8 != 不等於 雙目 變數1 != 變數2 從左至右 兩種語言都有
9 & 與運算 雙目 變數1&變數2 從左至右 兩種語言都有
10 ^ 異或運算 雙目 變數1^變數2 從左至右 兩種語言都有
11 | 或運算 雙目 變數1|變數2 從左至右 兩種語言都有
12 && 邏輯與 雙目 變數1&&變數2 從左至右 兩種語言都有
13 || 邏輯或 雙目 變數1||變數2 從左至右 兩種語言都有
14 ?: 條件運算 三目 變數1?變數2:變數3 從右至左 兩種語言都有
15 = 賦值 雙目 變數1=變數2 從右至左 兩種語言都有
15 += 加後賦值 雙目 變數1+=變數2 從右至左 兩種語言都有
15 -= 減後賦值 雙目 變數1-=變數2 從右至左 兩種語言都有
15 *= 乘後賦值 雙目 變數1*=變數2 從右至左 兩種語言都有
15 /= 除後賦值 雙目 變數1/=變數2 從右至左 兩種語言都有
15 %= 餘後賦值 雙目 變數1 %= 變數2 從右至左 兩種語言都有
15 <<= 左移賦值 雙目 變數1 <<= 變數2 從右至左 兩種語言都有
15 >>= 右移賦值 雙目 變數1 >>= 變數2 從右至左 兩種語言都有
15 &= 與後賦值 雙目 變數1 &= 變數2 從右至左 兩種語言都有
15 ^= 異或賦值 雙目 變數1 ^= 變數2 從右至左 兩種語言都有
15 |= 或後賦值 雙目 變數1 |= 變數2 從右至左 兩種語言都有
16 throw 拋異常 單目 throw 變數1 從右至左 C++專有
17 , 逗號運算 雙目 變數1,變數2 從左至右 兩種語言都有





























































注1: reinterpret_cast<>()和static_cast<>()貌似都是強制轉換,但是兩者是不同的

觀察下面的代碼:

class A {public:A(){ m_a = 1; }int m_a;};class B {public:B(){ m_b = 2; }int m_b;};class C : public A, public B {};void OperatorPriority(){C c;printf("%p, %p, %p\n", &c, reinterpret_cast<B*>(&c), static_cast <B*>(&c));B* b1 = &c, *b2 = reinterpret_cast<B*>(&c), *b3 = static_cast <B*>(&c);printf("%d, %d, %d\n", b1->m_b, b2->m_b, b3->m_b);}

執行OperatorPriority()函數後,輸出結果如下:

這是什麼意思?

這說明在轉換的時候reinterpret_cast<>()是無腦轉換,完全不管前因後果,進行強制轉換

static_cast<>()會先嘗試匹配一下,能匹配則會做出處理,否則則進行強制轉換

所以m_b static_cast<>()會輸出正確值,而reinterpret_cast<>()會給出一個錯誤值

但是為什麼強制類型轉換又可以正確輸出m_b呢?這就涉及到c++的多態特性,以後我會講到的。這裡只討論運算子,不做深入講解。

注2:首碼自增/減運算 和 尾碼自增/減運算

首碼自增/減 是這樣的 ++變數 --變數

尾碼自增/減 是這樣的 變數++ 變數--

有很多資料說尾碼自增/減運算 優先順序高於首碼

這個說得太簡單,實際情況非常複雜(也就是說這種說法完全是拍腦袋,沒有實踐的扯淡!)

首先,來看代碼:

從上面的代碼可以很明顯的看出,如果認為尾碼自增運算有所謂的高優先順序,那麼完全就說不通

首先++a--;語句根本就是個語法錯誤!首碼和尾碼運算子不能同時進行,所以也無法比較他們的優先順序。

不過這不能說明網上的優先順序說明是錯誤的,因為我們可以拿它們同級的其他運算子進行比較

注意test002函數 !運算是和首碼自增運算同級的運算子,按理說應該是先計算尾碼自增然後再計算非,

這樣就應該等價於a=!(a++) 即結果應該為0 。但是為什麼輸出的卻是1呢?

答案很複雜。上面真實的運算是這樣進行:

先計算計算a++ 即0++=1 儲存結果到a 然後按照a=0計算!a即 !0=1,再次儲存結果到a 導致的結果就是a最後變成了1

下面是該代碼的反組譯碼

a = !a++;00113EBD 8B 45 F8             mov         eax,dword ptr [a]  00113EC0 89 85 30 FF FF FF    mov         dword ptr [ebp-0D0h],eax  00113EC6 8B 4D F8             mov         ecx,dword ptr [a]  00113EC9 83 C1 01             add         ecx,1  00113ECC 89 4D F8             mov         dword ptr [a],ecx  00113ECF 83 BD 30 FF FF FF 00 cmp         dword ptr [ebp-0D0h],0  00113ED6 75 0C                jne         main+0B4h (0113EE4h)  00113ED8 C7 85 2C FF FF FF 01 00 00 00 mov         dword ptr [ebp-0D4h],1  00113EE2 EB 0A                jmp         main+0BEh (0113EEEh)  00113EE4 C7 85 2C FF FF FF 00 00 00 00 mov         dword ptr [ebp-0D4h],0  00113EEE 8B 95 2C FF FF FF    mov         edx,dword ptr [ebp-0D4h]  00113EF4 89 55 F8             mov         dword ptr [a],edx
從表面上看,尾碼++好像是優先運算的。但是我們不能只關注這點,而是要關注它對結果的影響
運算並不是先計算的就是高優先順序的——如果該運算更不不能影響結果
這個運算式的運算a++的結果是被捨棄了,也就是!運算子屏蔽了尾碼++!!!

是不是感覺邏輯有點亂?沒有關係,我們再看其他函數,這樣你就會更加淩亂!

看函數test003 test004

003的計算是這樣進行的:先計算a+a 即 0+0 得到0,再計算自增 即0++ 得到1 。最後進行賦值,取a++的值1

下面是實際的計算過程

00DD3E55 8B 45 F8             mov         eax,dword ptr [a]  00DD3E58 03 45 F8             add         eax,dword ptr [a]  00DD3E5B 89 45 F8             mov         dword ptr [a],eax  00DD3E5E 8B 4D F8             mov         ecx,dword ptr [a]  00DD3E61 83 C1 01             add         ecx,1  00DD3E64 89 4D F8             mov         dword ptr [a],ecx 
也就是說,這裡先計算了a+a,然後才計算的a++

這不是說明+運算子的優先順序高於尾碼++嗎!!

004的計算是這樣進行的:先計算2+a 即2+0 得到2,再計算自增,即2++,得到3

01383E89 8B 45 F8             mov         eax,dword ptr [a]  01383E8C 83 C0 02             add         eax,2  01383E8F 89 45 F8             mov         dword ptr [a],eax  01383E92 8B 4D F8             mov         ecx,dword ptr [a]  01383E95 83 C1 01             add         ecx,1  01383E98 89 4D F8             mov         dword ptr [a],ecx 
得到同樣的邏輯結果 +運算子優先順序高於尾碼++

現在我們來總結一下:

尾碼運算子 和!運算子在一起的時候,尾碼運算子會被屏蔽

尾碼運算子和+-*/等運算子在一起的時候,先計算其他,再計算自增

現在你是不是已經徹底糊塗了?

很好,這樣就對了。

因為我們現在得到一個結論:

1 那些所謂的優先順序,全部是扯淡,千萬不要指望優先順序能夠完全按照你的預想來執行

2 請用圓括弧安排好優先順序——只有這個是唯一可靠的夥伴!

下一節開始我將逐個對運算子進行分析和講解,敬請期待……
















zerglurker的C語言教程009——運算子詳解(一)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.