一. 問題的引出
今天看阿裡的筆試題,看到一個非常有意思的題目,但是很容易出錯。
題目:如下函數,在32bit系統foo(2^31-3)的值是:
Int foo(int x)
{
return x&-x;
}
解答:如果想要答對這道題目,首先要清楚C語言中符號的優先級別,負號(-)的優先級高於^,所以2^31-3=2^28,還有一個陷阱就是C語言中認為^為異或運算而不是冪函數,所以2^28=30,然後計算30 & -30得出結果。又因為計算機內存中的數據是以二進制的補碼形式存在的,所以參與位運算的數都是以補碼形式出現。所以需要把30和-30轉換為補碼之後再進行按位與運算,結果為2。我們還可以用程序看看執行過程中產生的x的值如下:
#include <iostream>
using namespace std;
int foo(int x){
cout << "x = " << x << endl;
return x & -x;
}
void main(){
int res = 0;
res = foo(2^31-3);
cout << "res = " << res << endl;
}
二. 字符的優先級
優先級
運算符
名稱或含義
使用形式
結合方向
說明
1
[]
數組下標
數組名[常量表達式]
左到右
()
圓括號
(表達式)/函數名(形參表)
.
成員選擇(對象)
對象.成員名
->
成員選擇(指針)
對象指針->成員名
2
-
負號運算符
-表達式
右到左
單目運算符
(類型)
強制類型轉換
(數據類型)表達式
++
自增運算符
++變量名/變量名++
單目運算符
--
自減運算符
--變量名/變量名--
單目運算符
*
取值運算符
*指針變量
單目運算符
&
取地址運算符
&變量名
單目運算符
!
邏輯非運算符
!表達式
單目運算符
~
按位取反運算符
~表達式
單目運算符
sizeof
長度運算符
sizeof(表達式)
3
/
除
表達式/表達式
左到右
雙目運算符
*
乘
表達式*表達式
雙目運算符
%
余數(取模)
整型表達式/整型表達式
雙目運算符
4
+
加
表達式+表達式
左到右
雙目運算符
-
減
表達式-表達式
雙目運算符
5
<<
左移
變量<<表達式
左到右
雙目運算符
>>
右移
變量>>表達式
雙目運算符
6
>
大於
表達式>表達式
左到右
雙目運算符
>=
大於等於
表達式>=表達式
雙目運算符
<
小於
表達式<表達式
雙目運算符
<=
小於等於
表達式<=表達式
雙目運算符
7
==
等於
表達式==表達式
左到右
雙目運算符
!=
不等於
表達式!= 表達式
雙目運算符
8
&
按位與
表達式&表達式
左到右
雙目運算符
9
^
按位異或
表達式^表達式
左到右
雙目運算符
10
|
按位或
表達式|表達式
左到右
雙目運算符
11
&&
邏輯與
表達式&&表達式
左到右
雙目運算符
12
||
邏輯或
表達式||表達式
左到右
雙目運算符
13
?:
條件運算符
表達式1? 表達式2:表達式3
右到左
三目運算符
14
=
賦值運算符
變量=表達式
右到左
/=
除後賦值
變量/=表達式
*=
乘後賦值
變量*=表達式
%=
取模後賦值
變量%=表達式
+=
加後賦值
變量+=表達式
-=
減後賦值
變量-=表達式
<<=
左移後賦值
變量<<=表達式
>>=
右移後賦值
變量>>=表達式
&=
按位與後賦值
變量&=表達式
^=
按位異或後賦值
變量^=表達式
|=
按位或後賦值
變量|=表達式
15
,
逗號運算符
表達式,表達式,…
左到右
從左向右順序運算
說明:同一優先級的運算符,運算次序由結合方向所決定。
三. 優先級口訣
括號成員第一; 括號運算符[]() 成員運算符. ->
全體單目第二; 所有的單目運算符比如++ -- +(正) -(負) 指針運算*&
乘除余三,加減四; 這個"余"是指取余運算即%
移位五,關系六; 移位運算符:<< >> ,關系:> < >= <= 等
等於(與)不等排第七; 即== !=
位與異或和位或; 這幾個都是位運算: 位與(&)異或(^)位或(|)
"三分天下"八九十;
邏輯或跟與; 邏輯運算符:|| 和 &&
十二和十一; 注意順序:優先級(||) 底於 優先級(&&)
條件高於賦值, 三目運算符優先級排到 13 位只比賦值運算符和","高
逗號運算級最低! 逗號運算符優先級最低