コンテンツにスキップ

英文维基 | 中文维基 | 日文维基 | 草榴社区

「CとC++の演算子」の版間の差分

出典: フリー百科事典『ウィキペディア(Wikipedia)』
削除された内容 追加された内容
m 曖昧さ回避ページへのリンクを修正
タグ: 2017年版ソースエディター
Cewbot (会話 | 投稿記録)
m Bot作業依頼: sourceタグをsyntaxhighlightタグに置換 (Category:非推奨のsourceタグを使用しているページ) - log
338行目: 338行目:


CやC++において、演算子の結合は、優先順位ではなく(各々の標準規格での)文法によって定められている。このため、僅かな差異が生じる場合がある。たとえば、Cの条件演算子は以下のように定義されている。
CやC++において、演算子の結合は、優先順位ではなく(各々の標準規格での)文法によって定められている。このため、僅かな差異が生じる場合がある。たとえば、Cの条件演算子は以下のように定義されている。
<source lang="c">
<syntaxhighlight lang="c">
logical-OR-expression ? expression : conditional-expression
logical-OR-expression ? expression : conditional-expression
</syntaxhighlight>
</source>
一方、C++では次のように定義されている。
一方、C++では次のように定義されている。
<source lang="c++">
<syntaxhighlight lang="c++">
logical-or-expression ? expression : assignment-expression
logical-or-expression ? expression : assignment-expression
</syntaxhighlight>
</source>
そのため、
そのため、
<pre>e = a ? b : c = d</pre>
<pre>e = a ? b : c = d</pre>
という式は、Cだと
という式は、Cだと
<source lang="c">
<syntaxhighlight lang="c">
e = ((a ? b : c) = d)
e = ((a ? b : c) = d)
</syntaxhighlight>
</source>
と解釈されて条件演算子の結果が左辺値でないことによるエラーとなるが、C++だと
と解釈されて条件演算子の結果が左辺値でないことによるエラーとなるが、C++だと
<source lang="cpp">
<syntaxhighlight lang="cpp">
e = (a ? b : (c = d))
e = (a ? b : (c = d))
</syntaxhighlight>
</source>
と解釈され、正しい式となる。
と解釈され、正しい式となる。


404行目: 404行目:


C++では、すべての比較演算子は真偽値を返す。
C++では、すべての比較演算子は真偽値を返す。
<source lang="cpp">
<syntaxhighlight lang="cpp">
bool a;
bool a;
int b = 1;
int b = 1;
int c = 2;
int c = 2;
a = b == c;
a = b == c;
</syntaxhighlight>
</source>
<code>==</code>はbool型の値を返すため、<code>==</code>演算子はif文などの中に限定されず、どこでも使用可能である。なお、<code>a = b == c;</code>は次のように書くのと同様の効果をもたらす。
<code>==</code>はbool型の値を返すため、<code>==</code>演算子はif文などの中に限定されず、どこでも使用可能である。なお、<code>a = b == c;</code>は次のように書くのと同様の効果をもたらす。
<source lang="cpp">
<syntaxhighlight lang="cpp">
bool a;
bool a;
int b = intに変換できる任意の値;
int b = intに変換できる任意の値;
419行目: 419行目:
else
else
a = false;
a = false;
</syntaxhighlight>
</source>


== 脚注 ==
== 脚注 ==

2020年7月5日 (日) 23:01時点における版

本項はC++C言語における演算子の一覧である。C++に存在するすべての演算子を掲示し、さらにCにも存在するかどうかを示している。なお、Cでは演算子の多重定義は不可能である。

&&||?:条件演算子)ならびに,コンマ演算子)は副作用完了点英語版を形成する。ただし、多重定義されていない場合に限る。

これらのうち、Cにも存在するものは、コンマ演算子と矢印演算子を除いて、JavaPerlC#PHPにも同じ優先順位・結合性を持って存在する。ただし、PHPの条件演算子は例外的に左から右への結合である。

演算子の表

この表においてa, b, cは有効な値 (リテラル・値・変数・戻り値)・オブジェクト名・左辺値を適宜意味する。なお、「多重定義可能か」はC++での話である。

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 a
sizeof(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 : da ? (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))

と解釈され、正しい式となる。

論理演算子の優先順位は問題があると指摘されている[1]。概念的には&|は算術演算子の+-のような存在である。しかし、a + b == 7(a + b) == 7と解釈されるが、a & b == 7という式はa & (b == 7)と解析されてしまう。ほかにも期待通りに解釈させるための括弧を必要とする場合がある。

C++の演算子の代替表現

C++では、一部の演算子に対して、全く同じに機能する代替表現を予約している[1]。代替表現はキーワードと同様に予約されている字句として扱われる。

代替表現 対応する演算子
and &&
bitand &
and_eq &=
or ||
bitor |
or_eq |=
xor ^
xor_eq ^=
not !
not_eq !=
compl ~

これらの代替表現は、記号的に等価として扱われ、どこでも記号を代替表現に置き換えても問題ない。置き換える先は、演算子としてではなく記号として扱われる。つまりbitandはビット積演算子だけでなくアドレス取得演算子の代わりに用いても機能するということである。

ANSI Cでは、これらを<iso646.h>でCプリプロセッサのマクロを用いて定義している。これとの互換性のために、C++ではヘッダ<iso646.h>と<ciso646>を用意しているが、中身は空である。

C++では、すべての比較演算子は真偽値を返す。

bool a;
int b = 1;
int c = 2;
a = b == c;

==はbool型の値を返すため、==演算子はif文などの中に限定されず、どこでも使用可能である。なお、a = b == c;は次のように書くのと同様の効果をもたらす。

bool a;
int b = intに変換できる任意の値;
int c = もう一つの任意値;
if (b == c)
    a = true;
else
    a = false;

脚注

  1. ^ SC22 Committee, The C++ Standards Working group (1998) (PDF). ISO/IEC 14882:1998(E), Programming Languages - C++. International standardization subcommittee for programming languages. pp. 40-41. http://plumber.gnu-darwin.org/home/pub/Documents/isoiec14882-c%2B%2B-standard.pdf 

関連項目