Namespaces
Variants

Assignment operators

From cppreference.net

代入演算子と複合代入演算子は、右側の値を使用して左側の変数を変更する二項演算子です。

演算子 演算子名 説明 等価表現
= 基本代入 a = b 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
% = 剰余代入 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 の両方が 算術型 を持つ場合。この場合 lhs volatile 修飾されている可能性がある または atomic (C11以降)
  • lhs rhs の両方が ポインタ 型(修飾子を無視して) 互換性のある 型を指している場合、または一方のポインタがvoidへのポインタであり、 変換 によって指し示される型に修飾子が追加されない場合。 lhs volatile または restrict (C99以降) 修飾されている可能性がある または atomic (C11以降)
  • lhs が(修飾されている可能性がある またはatomic (C11以降) )ポインタであり、 rhs NULL または nullptr_t (C23以降) のようなヌルポインタ定数である場合
  • lhs は(修飾されている可能性のある またはアトミック (C11以降) _Bool 型を持ち、 rhs はポインタ または nullptr_t (C23以降)
(C99以降)
  • lhs が(修飾またはアトミック型の可能性がある) nullptr_t 型を持ち、かつ rhs nullptr_t 型を持つ場合
(C23以降)

注記

rhs lhs がメモリ上で重複している場合(例:同じunionのメンバである場合)、その重複が正確でかつ型が 互換性がある 場合を除き、動作は未定義です。

配列は代入可能ではありませんが、構造体でラップされた配列は、同じ(または互換性のある)構造体型の別のオブジェクトに代入可能です。

lhs を更新する副作用は、値計算の 後に順序付けられます が、 lhs および rhs 自体の副作用は含まれず、オペランドの評価は通常通り互いに順序付けられていません(したがって、 i = ++ i のような式は未定義です)

代入は浮動小数点式から余分な範囲と精度を取り除きます( FLT_EVAL_METHOD を参照)。

C++では、代入演算子は左辺値式ですが、Cではそうではありません。

#include <stdio.h>
int main(void)
{
    // 整数
    int i = 1, j = 2, k = 3; // 初期化、代入ではない
    i = j = k;   // iとjの値は現在3
//  (i = j) = k; // エラー: 左辺値が必要
    printf("%d %d %d\n", i, j, k);
    // ポインタ
    const char c = 'A'; // 初期化; 代入ではない
    const char *p = &c;  // 初期化; 代入ではない
    const char **cpp = &p; // 初期化; 代入ではない
//  cpp = &p;   // エラー: char** は const char** に変換できない
    *cpp = &c;  // OK, char* は const char* に変換可能
    printf("%c \n", **cpp);
    cpp = 0;    // OK, ヌルポインタ定数は任意のポインタに変換可能
    // 配列
    int arr1[2] = {1,2}, arr2[2] = {3, 4};
//  arr1 = arr2; // エラー: 配列に代入できない
    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: 構造体でラップされた配列は代入可能
    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 は修飾またはアトミック型でも可)。 op + = または - = の場合、+および-演算子と同じ制限を持つポインタ型も受け入れる

lhs @= rhs は、 lhs = lhs @ ( rhs ) と完全に同じですが、 lhs が一度だけ評価される点が異なります。

lhs atomic 型を持つ場合、この操作はメモリ順序 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以降)
#include <stdio.h>
int main(void)
{
    int x = 10; 
    int hundred = 100; 
    int ten = 10; 
    int fifty = 50; 
    printf("%d %d %d %d\n", x, hundred, ten, fifty);
    hundred *= x; 
    ten     /= x; 
    fifty   %= x; 
    printf("%d %d %d %d\n", x, hundred, ten, fifty);
    return 0;
}

出力:

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 + = b
a - = b
a * = b
a / = b
a % = b
a & = b
a | = b
a ^ = b
a <<= b
a >>= b

++ a
-- a
a ++
a --

+ a
- a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

! a
a && b
a || b

a == b
a ! = b
a < b
a > b
a <= b
a >= b

a [ b ]
* a
& a
a - > b
a. b

a ( ... )
a, b
( type ) a
a ? b : c
sizeof


_Alignof
(C11以降)
(C23以前)

alignof
(C23以降)

関連項目

C++ documentation for Assignment operators