代入演算子
代入演算子および複合代入演算子は、右辺の値を使用して左辺の変数を変更する二項演算子です。
| Operator | 演算子名 | 例 | 説明 | 相当するもの |
|---|---|---|---|---|
| = | 単純代入 | a = b | a は b と等しくなる | N/A |
| += | 加算代入 | a += b | a は a と b の加算結果と等しくなる | a = a + b |
| -= | 減算代入 | a -= b | a は a から b を減算した結果と等しくなる | a = a - b |
| *= | 乗算代入 | a *= b | a は a と b の積と等しくなる | a = a * b |
| /= | 除算代入 | a /= b | a は a を b で割った結果と等しくなる | a = a / b |
| %= | 剰余代入 | a %= b | a は a を b で割った余りと等しくなる | a = a % b |
| &= | ビットAND代入 | a &= b | a は a と b のビットごとのAND結果と等しくなる | a = a & b |
| |= | ビットOR代入 | a |= b | a は a と b のビットごとのOR結果と等しくなる | a = a | b |
| ^= | ビットXOR代入 | a ^= b | a は a と b のビットごとのXOR結果と等しくなる | a = a ^ b |
| <<= | ビット左シフト代入 | a <<= b | a は a を b ビット左シフトした結果と等しくなる | a = a << b |
| >>= | ビット右シフト代入 | a >>= b | a は a を b ビット右シフトした結果と等しくなる | a = a >> b |
目次 |
[編集] 単純代入
単純代入演算子式は、次の形式をとります。
lhs = rhs |
|||||||||
ここで、
| lhs | - | あらゆる完全なオブジェクト型の変更可能な左辺値式 |
| rhs | - | lhs に暗黙的に変換可能、または lhs と互換性のある、あらゆる型の式 |
代入は、rhs の値から lhs の型への暗黙的な変換を実行し、その後 lhs が指定するオブジェクトの値を rhs の変換された値で置き換えます。
代入は、lhs に格納された値と同じ値を返します(たとえば、a = b = c のような式が可能です)。代入演算子の値カテゴリは左辺値ではありません(したがって、(a=b)=c のような式は無効です)。
rhs と lhs は、次のいずれかの条件を満たす必要があります。
- 両方の lhs と rhs が互換性のある構造体または共用体型である、または...
- rhs は lhs に暗黙的に変換可能でなければならず、これは以下を意味します。
- 両方の lhs と rhs が算術型であり、この場合 lhs は volatile修飾されていてもかまいません(C11以降、またはatomicでもかまいません)。
- 両方の lhs と rhs が互換性のある(修飾子を無視した)型のポインタであり、または一方のポインタが void へのポインタであり、変換によってポインタ先型に修飾子が付加されない場合。 lhs は volatile(C99以降、またはrestrictでもかまいません)修飾されていてもかまいません(C11以降、またはatomicでもかまいません)。
- lhs は(修飾子またはatomicであってもよい)ポインタであり、rhs はヌルポインタ定数(例: NULL、C23以降、またはnullptr_t 値)である。
|
(C99以降) |
|
(C23以降) |
[編集] 注記
rhs と lhs がメモリ上で重複している場合(例: 同じ共用体のメンバーである場合)、重複が完全に一致し、型が互換性がない限り、未定義の動作となります。
配列は代入可能ではありませんが、構造体にラップされた配列は、同じ(または互換性のある)構造体型の別のオブジェクトに代入可能です。
lhs を更新する副作用は、値の計算よりも後続します。ただし、lhs と rhs 自身の副作用やオペランドの評価は、通常どおり、互いに順序付けられていません(そのため、i=++i; のような式は未定義です)。
代入は、浮動小数点式から余分な範囲と精度を削除します(FLT_EVAL_METHOD を参照)。
C++ では、代入演算子は左辺値式ですが、C ではそうではありません。
#include <stdio.h> int main(void) { // integers int i = 1, j = 2, k = 3; // initialization, not assignment i = j = k; // values of i and j are now 3 // (i = j) = k; // Error: lvalue required printf("%d %d %d\n", i, j, k); // pointers const char c = 'A'; // initialization; not assignment const char *p = &c; // initialization; not assignment const char **cpp = &p; // initialization; not assignment // cpp = &p; // Error: char** is not convertible to const char** *cpp = &c; // OK, char* is convertible to const char* printf("%c \n", **cpp); cpp = 0; // OK, null pointer constant is convertible to any pointer // arrays int arr1[2] = {1,2}, arr2[2] = {3, 4}; // arr1 = arr2; // Error: cannot assign to an array printf("arr1[0]=%d arr1[1]=%d arr2[0]=%d arr2[1]=%d\n", arr1[0], arr1[1], arr2[0], arr2[1]); struct { int arr[2]; } sam1 = { {5, 6} }, sam2 = { {7, 8} }; sam1 = sam2; // OK: can assign arrays wrapped in structs printf("%d %d \n", sam1.arr[0], sam1.arr[1]); }
出力
3 3 3 A arr1[0]=1 arr1[1]=2 arr2[0]=3 arr2[1]=4 7 8
[編集] 複合代入
複合代入演算子式は、次の形式をとります。
| lhs op rhs | |||||||||
ここで、
| op | - | *=, /= %=, += -=, <<=, >>=, &=, ^=, |= のいずれか |
| lhs, rhs | - | 算術型を持つ式(lhs は修飾子またはatomicであってもよい)。ただし、op が += または -= の場合、+ および - と同じ制限でポインタ型も受け入れます。 |
lhs @= rhs という式は、lhs が一度だけ評価される点を除き、lhs = lhs @ ( rhs ) とまったく同じです。
|
lhs がアトミック型を持つ場合、操作はメモリ順序 memory_order_seq_cst を持つ単一のアトミック読み取り-変更-書き込み操作として動作します。 整数アトミック型の場合、複合代入 @= は次と同等です。 T1* addr = &lhs; T2 val = rhs; T1 old = *addr; T1 new; do { new = old @ val } while (!atomic_compare_exchange_strong(addr, &old, new); |
(C11 以降) |
出力
10 100 10 50 10 1000 1 0
[編集] 参照
- C17標準 (ISO/IEC 9899:2018)
- 6.5.16 代入演算子 (p: 72-73)
- C11標準 (ISO/IEC 9899:2011)
- 6.5.16 代入演算子 (p: 101-104)
- C99標準 (ISO/IEC 9899:1999)
- 6.5.16 代入演算子 (p: 91-93)
- C89/C90標準 (ISO/IEC 9899:1990)
- 3.3.16 代入演算子
[編集] 関連項目
| 共通の演算子 | ||||||
|---|---|---|---|---|---|---|
| 代入 | インクリメント デクリメント |
算術 | 論理 | 比較 | メンバ アクセス |
その他 |
|
a = b |
++a |
+a |
!a |
a == b |
a[b] |
a(...) |
[編集] 関連項目
| C++ドキュメント (代入演算子)
|