CとC++の演算子
From Wikipedia, the free encyclopedia
この表においてa, b, cは有効な値 (リテラル・値・変数・戻り値)・オブジェクト名・左辺値を適宜意味する。なお、「多重定義可能か」はC++での話である。
算術演算子 | |||
| 名称 | 構文 | 多重定義可能か | C言語に存在するか |
|---|---|---|---|
| 単項プラス | +a | Yes | Yes |
| 加算 | a + b | Yes | Yes |
| 前置インクリメント | ++a | Yes | Yes |
| 後置インクリメント | a++ | Yes | Yes |
| 加算代入 | a += b | Yes | Yes |
| 単項マイナス(負符号) | -a | Yes | Yes |
| 減算 | a - b | Yes | Yes |
| 前置デクリメント | --a | Yes | Yes |
| 後置デクリメント | a-- | Yes | Yes |
| 減算代入 | a -= b | Yes | Yes |
| 乗算 | a * b | Yes | Yes |
| 乗算代入 | a *= b | Yes | Yes |
| 除算 | a / b | Yes | Yes |
| 除算代入 | a /= b | Yes | Yes |
| 剰余 | a % b | Yes | Yes |
| 剰余代入 | a %= b | Yes | Yes |
比較演算子 | |||
| 名称 | 構文 | 多重定義可能か | C言語に存在するか |
| 小なり | a < b | Yes | Yes |
| 小なりイコール | a <= b | Yes | Yes |
| 大なり | a > b | Yes | Yes |
| 大なりイコール | a >= b | Yes | Yes |
| 非等価 | a != b | Yes | Yes |
| 等価 | a == b | Yes | Yes |
論理演算子 | |||
| 名称 | 構文 | 多重定義可能か | C言語に存在するか |
| 論理否定 | !a | Yes | Yes |
| 論理積 | a && b | Yes | Yes |
| 論理和 | a || b | Yes | Yes |
ビット演算子 | |||
| 名称 | 構文 | 多重定義可能か | C言語に存在するか |
| 左シフト | a << b | Yes | Yes |
| 左シフト代入 | a <<= b | Yes | Yes |
| 右シフト | a >> b | Yes | Yes |
| 右シフト代入 | a >>= b | Yes | Yes |
| ビット否定 | ~a | Yes | Yes |
| ビット積 | a & b | Yes | Yes |
| ビット積代入 | a &= b | Yes | Yes |
| ビット和 | a | b | Yes | Yes |
| ビット和代入 | a |= b | Yes | Yes |
| ビット排他的論理和 | a ^ b | Yes | Yes |
| ビット排他的論理和代入 | a ^= b | Yes | Yes |
型変換演算子 | |||
| 名称 | 構文 | 多重定義可能か | C言語に存在するか |
| 動的キャスト | dynamic_cast<type>(a) | No | No |
| 静的キャスト | static_cast<type>(a) | No | No |
| 定置性キャスト | const_cast<type>(a) | No | No |
| 強制キャスト | reinterpret_cast<type>(a) | No | No |
| 型変換(キャスト) | (type)a | Yes | Yes |
| 型変換(関数記法) | type(a) | Yes | No |
その他の演算子 | |||
| 名称 | 構文 | 多重定義可能か | C言語に存在するか |
| 単純代入 | a = b | Yes | Yes |
| 関数呼出 | a() | Yes | Yes |
| 配列添え字 | a[b] | Yes | Yes |
| 間接演算子 (デリファレンス) | *a | Yes | Yes |
| アドレス | &a | Yes | Yes |
| 間接メンバ | a->b | Yes | Yes |
| 直接メンバ | a.b | No | Yes |
| 間接メンバポインタ | a->*b | Yes | No |
| 直接メンバポインタ | a.*b | No | No |
| コンマ演算子 | a , b | Yes | Yes |
| 条件演算子 | a ? b : c | No | Yes |
| スコープ解決 | a::b | No | No |
| メンバへのポインタ | a::*b | No | No |
| アライメント (C11/C++11) | alignof(type) | No | Yes |
| sizeof | sizeof asizeof(type) | No | Yes |
| 型情報 | typeid(a)typeid(type) | No | No |
| 領域確保 | new type | Yes | No |
| 領域確保(配列) | new type[n] | Yes | No |
| 領域解放 | delete a | Yes | No |
| 領域解放(配列) | delete[] a | Yes | No |
演算子の優先順位
以下の表は、C++とCにおける優先順位と結合性を示したものである(なお、Java, Perl, PHPなど最近の言語の多くは同様の優先順位を持つ)。演算子は優先順位の低いものほど下のほうに掲載されている。同じセルに掲載されている演算子同士は同じ優先度を持つ。なお、たとえ多重定義しても、演算子の優先順位は変化しない。
CやC++において、演算子の構文は文脈自由文法にて定義されている。この表は、その構文より導き出されるものである。
この表では、正確に表現できていない部分が一部に存在する。たとえば、条件演算子は、代入やコンマ演算子より高い優先度を持つものの、中央のオペランドではそれらを含むすべての演算子の使用が可能である。すなわち、a ? b , c : dはa ? (b, c) : dと解釈される。また、(a ? b), (c : d)は意味を成さず、コンパイルエラーとなる。なお、括弧で囲われていない型変換式の結果はsizeofの対象となれない。つまり、sizeof (int) * xは(sizeof(int)) * xの意味となりsizeof ((int) * x)とはならない。
| 演算子 | 名称 | 結合性 |
|---|---|---|
:: |
スコープ解決 (C++のみ) | 左から右 |
++ -- |
後置インクリメント・デクリメント | |
() |
関数呼出し | |
[] |
配列添え字 | |
. |
直接メンバアクセス | |
-> |
間接メンバアクセス | |
typeid() |
実行時型情報 (C++のみ) | |
const_cast |
型変換 (C++のみ) | |
dynamic_cast |
型変換 (C++のみ) | |
reinterpret_cast |
型変換 (C++のみ) | |
static_cast |
型変換 (C++のみ) | |
++ -- |
前置インクリメント・デクリメント | 右から左 |
+ - |
単項プラスとマイナス | |
! ~ |
論理否定とビット否定 | |
(type) |
型変換 | |
* |
間接演算子 (デリファレンス) | |
& |
アドレス | |
sizeof |
記憶量 | |
new new[] |
動的記憶域確保 (C++のみ) | |
delete delete[] |
動的記憶域解放 (C++のみ) | |
.* ->* |
メンバへのポインタ (C++のみ) | 左から右 |
* / % |
乗算・除算・剰余算 | |
+ - |
加算・減算 | |
<< >> |
左シフト・右シフト | |
< <= |
(関係演算子)小なり・小なりイコール | |
> >= |
大なり・大なりイコール | |
== != |
等価・非等価 | |
& |
ビット積 | |
^ |
ビット排他的論理和 | |
| |
ビット和 | |
&& |
論理積 | |
|| |
論理和 | |
c ? t : f |
条件演算子 | 右から左 ( throwは結合しない) |
= |
単純代入 | |
+= -= |
加算代入・減算代入 | |
*= /= %= |
乗算代入・除算代入・剰余代入 | |
<<= >>= |
左シフト代入・右シフト代入 | |
&= ^= |= |
ビット積代入・ビット排他的論理和代入・ビット和代入 | |
throw |
送出代入 (例外送出: C++のみ) | |
, |
コンマ演算子 | 左から右 |
補足
優先順位の表は、括弧で括られていない式において結びつく順序を決める。
++x * 3は優先順位の規則がなければ曖昧である。しかし、実際には、優先順位によってxは*より++に結びつくので、(++x) * 3と解釈される。- 同様に、
3 * x++ではxのみがインクリメントの対象となる。 - 優先順位と結合性の問題は上記のダイアグラム[要追加記述]のように一般化できる。コンパイラの目標はこのようなダイアグラムを式として解決することである。この図は各単項の演算子(ここではそれぞれ
3 + ( . ),2 * ( . ),( . )++,( . )[i]と表記する)がyへ結合しようとしていることを表す。優先順位の表から、各部分式は最終的に、( . )[i]はyへ、( . )++はy[i]へ、2 * ( . )は(y[i])++へ、3 + ( . )は2 * ((y[i])++)という結合にしか成り得ないことが決定される。- 注意: 優先順位からは部分式が「何」に対して作用するかを決めるが、「いつ」作用するかには関与しない。上の
2 * ((y[i])++)という例では、優先順位と直接には関係なく、単に演算のためにその値が必要であるという(データフロー的な)理由により、後置++演算子がy[i]より後に作用する、ということしか明確ではない。
- 注意: 優先順位からは部分式が「何」に対して作用するかを決めるが、「いつ」作用するかには関与しない。上の
CやC++において、演算子の結合は、優先順位ではなく(各々の標準規格での)文法によって定められている。このため、僅かな差異が生じる場合がある。たとえば、Cの条件演算子は以下のように定義されている。
logical-OR-expression ? expression : conditional-expression
一方、C++では次のように定義されている。
logical-or-expression ? expression : assignment-expression
そのため、
e = a ? b : c = d
という式は、Cだと
e = ((a ? b : c) = d)
と解釈されて条件演算子の結果が左辺値でないことによるエラーとなるが、C++だと
e = (a ? b : (c = d))
と解釈され、正しい式となる。
論理演算子の優先順位は問題があると指摘されている。概念的には&と|は算術演算子の+と-のような存在である。しかし、a + b == 7は(a + b) == 7と解釈されるが、a & b == 7という式はa & (b == 7)と解析されてしまう。ほかにも期待通りに解釈させるための括弧を必要とする場合がある。