C和C++運算子
外觀
所有的C語言運算符都被C++語言支持。C語言不支持運算符重載。
在不重載時,運算符&&
、||
、,
(逗號運算符),在第一個操作數求值之後有一個順序點。
大部分C與C++運算符也可用於其它程序設計語言如C#、Java、Perl、PHP等,具有相同的優先級、結合性與語義。
運算子優先級
[編輯]優先級 | 運算子 | 敘述 | 示例 | 重載性 | 結合性 |
---|---|---|---|---|---|
1
|
::
|
作用域解析(C++專有) | Class::age = 2;
|
否 | 由左至右 |
2
|
++
|
後綴遞增 | i++
|
||
--
|
後綴遞減 | i--
|
|||
()
|
函數調用或函數調用形式的類型轉換 | int x = f();
|
|||
[]
|
數組訪問 | array[4] = 2;
|
|||
.
|
以對象方式訪問成員 | obj.age = 34;
|
否 | ||
->
|
以指針方式訪問成員 | ptr->age = 34;
|
|||
dynamic_cast
|
運行時檢查類型轉換(C++專有) | Y& y = dynamic_cast<Y&>(x);
|
否 | ||
static_cast
|
未經檢查的類型轉換(C++專有) | Y& y = static_cast<Y&>(x);
|
否 | ||
reinterpret_cast
|
重定義類型轉換(C++專有) | int const* p = reinterpret_cast<int const*>(0x1234);
|
否 | ||
const_cast
|
更改非常量屬性(C++專有) | int* q = const_cast<int*>(p);
|
否 | ||
typeid
|
獲取類型信息(C++專有) | std::type_info const& t = typeid(x);
|
否 | ||
3
|
++
|
前綴遞增 | ++i
|
由右至左 | |
--
|
前綴遞減 | --i
|
|||
+
|
一元正號 | int i = +1;
|
|||
-
|
一元負號 | int i = -1;
|
|||
! not
|
邏輯非! 的備用拼寫
|
if (!done) …
|
|||
~ compl
|
按位取反~ 的備用拼寫
|
flag1 = ~flag2;
|
|||
(type)
|
強制類型轉換 | int i = (int)floatNum;
|
|||
*
|
取指針指向的值 | int data = *intPtr;
|
|||
&
|
取變量的地址 | int *intPtr = &data;
|
|||
sizeof
|
某某的大小 | size_t s = sizeof(int);
|
否 | ||
new
|
動態內存分配(C++專有) | long* pVar = new long;
|
|||
new[]
|
動態數組內存分配(C++專有) | long* array = new long[20];
|
|||
delete
|
動態內存釋放(C++專有) | delete pVar;
|
|||
delete[]
|
動態數組內存釋放(C++專有) | delete [] array;
|
|||
4
|
.*
|
成員對象選擇(C++專有) | obj.*var = 24;
|
否 | 由左至右 |
->*
|
成員指針選擇(C++專有) | ptr->*var = 24;
|
|||
5
|
*
|
乘法 | int i = 2 * 4;
|
||
/
|
除法 | float f = 10.0 / 3.0;
|
|||
%
|
模數(取餘數) | int rem = 4 % 3;
|
|||
6
|
+
|
加法 | int i = 2 + 3;
|
||
-
|
減法 | int i = 5 - 1;
|
|||
7
|
<<
|
位元左移 | int flags = 33 << 1;
|
||
>>
|
位元右移 | int flags = 33 >> 1;
|
|||
8
|
<=>
|
三路比較(C++20) | auto flags = 33 <=> 1;
|
||
9
|
<
|
小於關係 | if (i < 42) …
|
||
<=
|
小於等於關係 | if (i <= 42) ...
|
|||
>
|
大於關係 | if (i > 42) …
|
|||
>=
|
大於等於關係 | if (i >= 42) ...
|
|||
10
|
==
|
等於關係 | if (i == 42) ...
|
||
!= not_eq
|
不等於關係!= 的備用拼寫
|
if (i != 42) …
|
|||
11
|
& bitand
|
位元 AND& 的備用拼寫
|
flag1 = flag2 & 42;
|
||
12
|
^ xor
|
位元 XOR(獨占or)^ 的備用拼寫
|
flag1 = flag2 ^ 42;
|
||
13
|
| bitor
|
位元 OR(包含or)| 的備用拼寫
|
flag1 = flag2 | 42;
|
||
14
|
&& and
|
邏輯 AND&& 的備用拼寫
|
if (conditionA && conditionB) …
|
||
15
|
|| or
|
邏輯 OR|| 的備用拼寫
|
if (conditionA || conditionB) ...
|
||
16
|
c?t:f
|
三元條件運算 | int i = a > b ? a : b;
|
否 | 由右至左 |
17
|
=
|
直接賦值 | int a = b;
|
||
+=
|
以和賦值 | a += 3;
|
|||
-=
|
以差賦值 | b -= 4;
|
|||
*=
|
以積賦值 | a *= 5;
|
|||
/=
|
以商賦值 | a /= 2;
|
|||
%=
|
以取餘數賦值 | a %= 3;
|
|||
<<=
|
以位元左移賦值 | flags <<= 2;
|
|||
>>=
|
以位元右移賦值 | flags >>= 2;
|
|||
&= and_eq
|
以位元AND賦值&= 的備用拼寫
|
flags &= new_flags;
|
|||
^= xor_eq
|
以位元XOR賦值^= 的備用拼寫
|
flags ^= new_flags;
|
|||
|= or_eq
|
以位元OR賦值|= 的備用拼寫
|
flags |= new_flags;
|
|||
18
|
throw
|
拋出異常 | throw EClass("Message");
|
否 | |
19
|
,
|
逗號運算子 | for (i = 0, j = 0; i < 10; i++, j++) …
|
由左至右 |
列表
[編輯]在本表中,a
、b
和c
代表有效值(來自變數或返回值的逐字常數或數值)、物件名稱,或適當的左值。
算術運算子
[編輯]運算子名稱 | 語法 | 可重載 | C語言裡有 |
---|---|---|---|
一元正號 | +a |
是 | 是 |
加法(總和) | a + b |
是 | 是 |
前綴遞增 | ++a |
是 | 是 |
後綴遞增 | a++ |
是 | 是 |
以加法賦值 | a += b |
是 | 是 |
一元負號(取反) | -a |
是 | 是 |
減法(差) | a - b |
是 | 是 |
前綴遞減 | --a |
是 | 是 |
後綴遞減 | a-- |
是 | 是 |
以減法賦值 | a -= b |
是 | 是 |
乘法(乘積) | a * b |
是 | 是 |
以乘法賦值 | a *= b |
是 | 是 |
除法(分之) | a / b |
是 | 是 |
以除法賦值 | a /= b |
是 | 是 |
模數(餘數) | a % b |
是 | 是 |
以模數賦值 | a %= b |
是 | 是 |
比較運算子
[編輯]運算子名稱 | 語法 | 可重載 | C語言裡有 |
---|---|---|---|
小於 | a < b |
是 | 是 |
小於或等於 | a <= b |
是 | 是 |
大於 | a > b |
是 | 是 |
大於或等於 | a >= b |
是 | 是 |
不等於 | a != b |
是 | 是 |
等於 | a == b |
是 | 是 |
邏輯取反 | !a |
是 | 是 |
邏輯 AND | a && b |
是 | 是 |
邏輯 OR | a || b |
是 | 是 |
三路比較 | a <=> b |
是 | 否 |
位元運算子
[編輯]運算子名稱 | 語法 | 可重載 | C語言裡有 |
---|---|---|---|
位元左移 | a << b |
是 | 是 |
以位元左移賦值 | a <<= b |
是 | 是 |
位元右移 | a >> b |
是 | 是 |
以位元右移賦值 | a >>= b |
是 | 是 |
位元一的補數 | ~a |
是 | 是 |
位元 AND | a & b |
是 | 是 |
以位元 AND 賦值 | a &= b |
是 | 是 |
位元 OR | a | b |
是 | 是 |
以位元 OR 賦值 | a |= b |
是 | 是 |
位元 XOR | a ^ b |
是 | 是 |
以位元 XOR 賦值 | a ^= b |
是 | 是 |
其它運算子
[編輯]運算子名稱 | 語法 | 可重載 | C語言裡有 |
---|---|---|---|
基本賦值 | a = b |
是 | 是 |
函式呼叫 | a() |
是 | 是 |
陣列下標 | a[b] |
是 | 是 |
間接(向下參考) | *a |
是 | 是 |
的位址(參考) | &a |
是 | 是 |
成員指標 | a->b |
是 | 是 |
成員 | a.b |
否 | 是 |
間接成員指標 | a->*b |
是 | 否 |
間接成員 | a.*b |
否 | 否 |
轉換 | (type) a |
是 | 是 |
逗號 | a , b |
是 | 是 |
三元條件 | a ? b : c |
否 | 是 |
作用域解析 | a::b |
否 | 否 |
的大小 | sizeof a |
否 | 是 |
類型識別 | typeid type |
否 | 否 |
分配儲存區 | new type |
是 | 否 |
解除分配儲存區 | delete a |
是 | 否 |
語言擴展
[編輯]運算子名稱 | 語法 | 可重載 | C語言裡有 | 提供者 |
---|---|---|---|---|
標籤值 | && label |
否 | 是 | GCC |
取得型態 | typeof a typeof(expr) |
否 | 是 | GCC |
最小/最大值 | a <? b a >? b |
否 | 否 | GCC < 4.3 |
註解
[編輯]在C和C++中對運算子的約束,是語言的語法規範因素所指定的(在對應的標準中),而不是優先級列表。這造成了一些微妙的衝突。例如,在C中,條件表達式的語法是:
邏輯-OR-表達式 ? 表達式 : 條件-表達式
在C++中則是:
邏輯-or-表達式 ? 表達式 : 賦值-表達式
因此,這個表達式:
e = a ? b : c = d
兩個語言的語法分析結果並不相同。在C中,這個表達式被解析為:
e = ((a ? b : c) = d)
這是一個錯誤的語義,因為條件-表達式的結果並不是一個左值。在C++中,則解析為:
e = (a ? b : (c = d))
這是一個有效的表達式。
位元邏輯運算子的優先級一直受到批評[1]。在觀念裡,&和|是類似於+和*的數值運算子。但是,表達式
a & b == 7
意謂
a & (b == 7)
而
a + b == 7
意謂
(a + b) == 7
這就需要經常使用圓括號,以免有意料之外的結果。
一元正號運算符可用於操作數表達式的類型提升。例如下例:
template <class T> void f(T const& a, T const& b){};
int main() {
int a[2];
int b[3];
f(a, b); // won't work! different values for "T"!
f(+a, +b); // works! T is "int*" both
}
安全問題
[編輯]下表指出了各個運算符可能導致的安全問題:
符號 | 安全性 | 符號 | 安全性 | 符號 | 安全性 | 符號 | 安全性 |
---|---|---|---|---|---|---|---|
+ | 溢位,包裹,循環 | -= | 溢位,包裹,循環,截裁 | >> | 無 | >= | 無 |
- | 溢位,包裹,循環 | *= | 溢位,包裹,循環,截裁 | & | 無 | == | 無 |
* | 溢位,包裹,循環 | /= | 溢位,截裁 | ~ | 無 | != | 無 |
% | 溢位 | <<= | 溢位,包裹,循環,截裁 | ! | 無 | && | 無 |
++ | >>= | 截裁 | un+ | 無 | || | 無 | |
-- | &= | 截裁 | un- | 溢位,包裹,截裁 | ?: | 無 | |
= | |= | 截裁 | < | 無 | <=> | ||
+= | << | 溢位,包裹,截裁 | > | 無 |
參閱
[編輯]參考資料
[編輯]- ^ The Development of the C Language. [2007-03-01]. (原始內容存檔於2015-02-03).
外部連結
[編輯]- Experimental results(頁面存檔備份,存於網際網路檔案館) showing that developers have poor knowledge of binary operator precedence.
- Basic types & Operators(頁面存檔備份,存於網際網路檔案館)