Namespaces
Variants

Implicit conversions

From cppreference.net

式が異なる型の値が期待される文脈で使用される場合、 変換 が発生することがあります:

int n = 1L; // 式 1L は long 型だが、int 型が期待されている
n = 2.1; // 式 2.1 は double 型だが、int 型が期待されている
char* p = malloc(10); // 式 malloc(10) は void* 型だが、char* 型が期待されている

変換は以下の状況で行われます:

目次

代入による変換

  • 代入演算子では、右辺オペランドの値が左辺オペランドの非修飾型に変換されます。
  • スカラー初期化では、初期化子式の値が初期化されるオブジェクトの非修飾型に変換されます。
  • プロトタイプを持つ関数への関数呼び出し式では、各引数式の値が対応するパラメータの非修飾宣言型に変換されます。
  • return文では、 return のオペランドの値が関数の戻り値の型を持つオブジェクトに変換されます。

実際の代入では、変換に加えて、浮動小数点型から余分な範囲と精度を除去し、重複を禁止することに注意してください。これらの特性は、代入による変換の場合には適用されません。

デフォルト引数プロモーション

関数呼び出し式において、呼び出しが行われる場合 function call expression

1) プロトタイプのない 関数 (C23まで)
2) 可変個引数関数において、引数式が省略記号パラメータに対応する末尾引数のいずれかである場合。

整数型の各引数は 整数昇格 を受け、 float 型の各引数は暗黙的に double 型に変換されます。

int add_nums(int count, ...);
int sum = add_nums(2, 'c', true); // add_numsは3つのintで呼び出される: (2, 99, 1)

float complex および float imaginary は、この文脈では double complex および double imaginary に昇格されないことに注意してください。

(C99以降)

通常の算術変換

以下の算術演算子の引数は、 共通実数型  を取得するために暗黙の型変換を受けます。これは計算が実行される型です:

1) 一方のオペランドが十進浮動小数点型の場合、他方のオペランドは標準浮動小数点型、

複素数型、または虚数型であってはならない。

  • まず、いずれかのオペランドの型が _Decimal128 の場合、他方のオペランドは _Decimal128 に変換される。
  • そうでない場合、いずれかのオペランドの型が _Decimal64 の場合、他方のオペランドは _Decimal64 に変換される。
  • そうでない場合、いずれかのオペランドの型が _Decimal32 の場合、他方のオペランドは _Decimal32 に変換される。
(C23以降)
2) それ以外の場合、一方のオペランドが long double long double complex または long double imaginary (C99以降) である場合、他方のオペランドは以下のように暗黙的に変換されます:
  • 整数型または実浮動小数点型は long double に変換
(C99以降)
3) それ以外の場合、一方のオペランドが double double complex または double imaginary (C99以降) の場合、他方のオペランドは以下のように暗黙的に変換されます:
  • 整数型または実浮動小数点型は double に変換
(C99以降)
4) それ以外の場合、一方のオペランドが float float complex または float imaginary (C99以降) の場合、他方のオペランドは以下のように暗黙的に変換されます:
  • 整数型は float に変換(実数型で可能なのはfloatのみであり、その場合はそのまま維持)
(C99以降)
5) それ以外の場合、両オペランドは整数型である。両オペランドは 整数プロモーション を受ける。その後、整数プロモーション後、以下のいずれかのケースが適用される:
  • 型が同じ場合、その型が共通型となる。
  • それ以外の場合、型が異なる:
    • 型が同じ符号性(両方符号付きまたは両方符号なし)を持つ場合、 変換ランク [1] が小さい方の型のオペランドが暗黙的に [2] 他方の型に変換される。
    • それ以外の場合、オペランドは異なる符号性を持つ:
      • 符号なし型の 変換ランク が符号付き型のランク以上の場合、符号付き型のオペランドは符号なし型に暗黙的に変換される。
      • それ以外の場合、符号なし型の 変換ランク が符号付き型より小さい:
        • 符号付き型が符号なし型のすべての値を表現できる場合、符号なし型のオペランドは符号付き型に暗黙的に変換される。
        • それ以外の場合、両オペランドは符号付きオペランドの型に対応する符号なし型への暗黙的変換を受ける。
  1. ランク付けの規則については以下の 整数プロモーション を参照。
  2. 以下の 暗黙的変換セマンティクス の「整数変換」を参照。
1.f + 20000001; // intはfloatに変換され、20000000.00となる
                // 加算後、floatに丸められて20000000.00となる
(char)'a' + 1L; // まず、char 'a'(97)がintに昇格される
                // 異なる型: intとlong
                // 同じ符号付き性: 両方とも符号付き
                // 異なるランク: longはintより上位のランク
                // したがって、int 97はlong 97に変換される
                // 結果は型signed longの97 + 1 = 98
2u - 10; // 異なる型: unsigned intとsigned int
         // 異なる符号付き性
         // 同じランク
         // したがって、signed int 10はunsigned int 10に変換される
         // 算術演算は符号なし整数に対して実行されるため
         // (「算術演算子」トピック参照)、計算は(2 - 10) modulo (2のn乗)
         // ここでnはunsigned intの値ビット数
         // unsigned intが32ビット長で、そのオブジェクト表現にパディングビットがない場合
         // 結果は(-8) modulo (2の32乗) = 4294967288(型unsigned int)
5UL - 2ULL; // 異なる型: unsigned longとunsigned long long
            // 同じ符号付き性
            // 異なるランク: unsigned long longのランクが上位
            // したがって、unsigned long 5はunsigned long long 5に変換される
            // 算術演算は符号なし整数に対して実行されるため
            // (「算術演算子」トピック参照)
            // unsigned long longが64ビット長の場合、
            // 結果は(5 - 2) modulo (2の64乗) = 3(型unsigned long long)
0UL - 1LL; // 異なる型: unsigned longとsigned long long
           // 異なる符号付き性
           // 異なるランク: signed long longのランクが上位
           // ULONG_MAX > LLONG_MAXの場合、signed long longはすべてのunsigned longを
           // 表現できないため、最終ケース: 両オペランドはunsigned long longに変換される
           // unsigned long 0はunsigned long long 0に変換される
           // long long 1はunsigned long long 1に変換される
           // 算術演算は符号なし整数に対して実行されるため
           // (「算術演算子」トピック参照)
           // unsigned long longが64ビット長の場合、
           // 計算は(0 - 1) modulo (2の64乗)
           // したがって、結果は18446744073709551615(ULLONG_MAX)(型unsigned long long)

結果の型は以下のように決定されます:

  • 両方のオペランドが複素数の場合、結果の型は複素数型です;
  • 両方のオペランドが虚数の場合、結果の型は虚数型です;
  • 両方のオペランドが実数の場合、結果の型は実数型です;
  • 2つの浮動小数点オペランドが異なる型領域(複素数 vs 実数、複素数 vs 虚数、または虚数 vs 実数)を持つ場合、結果の型は複素数型です。
double complex z = 1 + 2*I;
double f = 3.0;
z + f; // z remains as-is, f is converted to double, the result is double complex
(C99以降)

いつものように、浮動小数点演算子の結果は、その型で示される範囲と精度よりも大きい範囲と精度を持つ可能性があります( FLT_EVAL_METHOD を参照)。

注記: 実数と虚数のオペランドは暗黙的に複素数に変換されません。なぜなら、そのようにすると追加の計算が必要となり、無限大、NaN、符号付きゼロを含む特定の場合において望ましくない結果を生じるためです。例えば、実数が複素数に変換される場合、2.0×(3.0+i∞) は (2.0+i0.0)×(3.0+i∞) ⇒ (2.0×3.0–0.0×∞) + i(2.0×∞+0.0×3.0) ⇒ NaN+i∞ と評価され、正しい結果である 6.0+i∞ にはなりません。虚数が複素数に変換される場合、i2.0×(∞+i3.0) は (0.0+i2.0) × (∞+i3.0) ⇒ (0.0×∞ – 2.0×3.0) + i(0.0×3.0 + 2.0×∞) ⇒ NaN + i∞ と評価され、正しい結果である –6.0 + i∞ にはなりません。

(C99以降)

注記: 通常の算術変換に関わらず、これらの規則で指定される型よりも狭い型で計算が行われる可能性が常にあります( as-if rule に基づきます)。

値変換

Lvalue変換

任意の非配列型の 左辺値式 は、以下のいずれでもない文脈で使用される場合

lvalue変換  を受けます:型は同じままですが、 const / volatile / restrict 修飾子および atomic プロパティ(存在する場合)が失われます。値は同じままですが、lvalueプロパティを失います(アドレスが取得できなくなる可能性があります)。

lvalueが不完全型の場合、動作は未定義です。

左辺値がそのアドレスが一度も取得されなかった自動記憶域期間のオブジェクトを指定し、かつそのオブジェクトが未初期化(初期化子で宣言されておらず、使用前に代入が実行されていない)である場合、動作は未定義です。

この変換は、オブジェクトの値のメモリロードをその位置からモデル化します。

volatile int n = 1;
int x = n;            // nに対するlvalue変換によりnの値が読み取られる
volatile int* p = &n; // lvalue変換は発生しない: nの値は読み取られない

配列からポインタへの変換

任意の 左辺値式 (C99まで) (C99以降) 配列型 のものは、以下の文脈以外で使用される場合

その配列の最初の要素を指す非左値ポインタへの変換を受けます。

配列が register として宣言された場合、動作は未定義です。

非左値配列、またはその要素のいずれかは 、アクセスできません (C99まで) 一時的寿命 を持ちます (C99以降)

int a[3], b[3][4];
int* p = a;      /* &a[0]への変換 */
int (*q)[4] = b; /* &b[0]への変換 */
struct S
{
    int a[1];
};
struct S f(void)
{
    struct S result = {{0}}; /* C99以降では{0} */
    return result;
}
void g(void)
{
    int* p = f().a;    /* C99まではエラー; C99以降はOK */
    int n  = f().a[0]; /* C99まではエラー; C99以降はOK */
    f().a[0] = 13;     /* C99まではエラー; C99以降は未定義動作 */
    (void)p, (void)n;
}
int main(void) { return 0; }

関数からポインタへの変換

関数指示子式は、以下のいずれかの文脈以外で使用される場合、

式によって指定される関数への非左値ポインタへの変換が行われます。

int f(int);
int (*p)(int) = f; // fへの変換
(***p)(1); // fへの繰り返し逆参照と&fへの変換

暗黙的変換セマンティクス

暗黙の変換は、 as if by assignment  または usual arithmetic conversion  のいずれであっても、2つの段階で構成されます:

1) 値変換(該当する場合)、
2) 以下の変換のいずれか(対象の型を生成できる場合)。

互換性のある型

任意の型の値から任意の 互換性のある型 への変換は常に無操作であり、表現を変更しません。

uint8_t (*a)[10];         // uint8_tがunsigned charへのtypedefである場合
unsigned char (*b)[] = a; // これらのポインタ型は互換性があります

整数プロモーション

整数昇格は、intの ランク 以下の ランク を持つ任意の整数型の値、または型が ビットフィールド _Bool (C23まで) bool (C23以降) int signed int unsigned int の値から、型 int または unsigned int の値への暗黙的な変換です。

元の型(または元のビットフィールド)の値の範囲全体を int が表現できる場合、値は int 型に変換されます。それ以外の場合、値は unsigned int に変換されます。

ビット精度整数型のビットフィールドからの値は、対応するビット精度整数型に変換されます。それ以外の場合、ビット精度整数型は整数プロモーション規則の対象外となります。

(C23以降)

整数プロモーションは値(符号を含む)を保持します:

int main(void)
{
    void f(); // 旧形式の関数宣言
              // C23以降、void f(...) は昇格に関して同じ動作を持つ
    char x = 'a'; // intからcharへの整数変換
    f(x); // charからintへの整数昇格
}
void f(x) int x; {} // 関数はintを期待する

rank はすべての integer type の特性であり、以下のように定義されます:

1) すべての符号付き整数型のランクは異なり、その精度とともに増加する: signed char のランク < short のランク < int のランク < long int のランク < long long int のランク
2) すべての符号付き整数型のランクは、対応する符号なし整数型のランクと等しい
3) 同じサイズの拡張整数型 またはビット精度整数型 (C23以降) よりも、標準整数型のランクは常に高い __int64 のランク < long long int のランク、しかし long long のランク < __int128 のランク(規則 (1) による)
4) char の順位は signed char の順位および unsigned char の順位と等しい
5) _Bool (C23まで) bool (C23以降) の順位は他の標準整数型のいずれの順位よりも小さい
6) 任意の列挙型のランクは、その互換性のある整数型のランクと等しい
7) ランキングは推移的である:T1のランク < T2のランク かつ T2のランク < T3のランク ならば T1のランク < T3のランク。
8) ビット精度符号付き整数型の順位は、より小さい幅を持つ任意の標準整数型またはより小さい幅を持つ任意のビット精度整数型の順位よりも大きくなければならない。
9) 同じ幅を持つ拡張整数型に対する任意のビット精度整数型の順位は実装定義である。
(C23以降)
10) 上記でカバーされていない拡張整数型の相対的順位付けに関するあらゆる側面は実装定義である。

注:整数プロモーションは以下の場合にのみ適用されます

  • 通常の算術変換の一部として(上記参照)、
  • デフォルト引数プロモーションの一部として(上記参照)、
  • 単項算術演算子 + および - のオペランドに対して、
  • 単項ビット演算子 ~ のオペランドに対して、
  • シフト演算子 << および >> の両方のオペランドに対して。

ブーリアン変換

任意のスカラー型の値は暗黙的に _Bool (C23まで) bool (C23以降) に変換できます。 値がゼロの整数定数式と等しいと比較される値 (C23まで) ゼロ(算術型の場合)、ヌル(ポインタ型の場合)、または nullptr_t 型を持つ値 (C23以降) 0 (C23まで) false (C23以降) に変換され、他のすべての値は 1 (C23まで) true (C23以降) に変換されます。

bool b1 = 0.5;              // b1 == 1 (0.5 converted to int would be zero)
bool b2 = 2.0*_Imaginary_I; // b2 == 1 (but converted to int would be zero)
bool b3 = 0.0 + 3.0*I;      // b3 == 1 (but converted to int would be zero)
bool b4 = 0.0 / 0.0;        // b4 == 1 (NaN does not compare equal to zero)
bool b5 = nullptr;          // b5 == 0 (since C23: nullptr is converted to false)
(C99以降)

整数変換

任意の整数型の値は、他の任意の整数型に暗黙的に変換できます。上位の昇格と論理値変換でカバーされる場合を除き、規則は以下の通りです:

  • ターゲット型が値を表現できる場合、値は変更されません。
  • そうでない場合、ターゲット型が符号なしの場合、値は 2 b
    (ここで b はターゲット型の値ビット数)を繰り返し減算または加算し、結果がターゲット型に収まるようにします。つまり、符号なし整数はモジュロ演算を実装します。
  • そうでない場合、ターゲット型が符号付きの場合、動作は実装定義です(シグナルの発生を含む場合があります)。
char x = 'a'; // int → char、結果は変更なし
unsigned char n = -123456; // ターゲットはunsigned、結果は192(つまり -123456+483*256)
signed char m = 123456;    // ターゲットはsigned、結果は実装定義
assert(sizeof(int) > -1);  // assert失敗:
                           // operator > は-1をsize_tへの変換を要求、
                           // ターゲットはunsigned、結果はSIZE_MAX

実数浮動小数点-整数変換

任意の実浮動小数点型の有限値は、任意の整数型に暗黙的に変換できます。前述のブーリアン変換でカバーされる場合を除き、規則は以下の通りです:

  • 小数部分は切り捨てられます(ゼロ方向への切り捨て)。
  • 結果の値がターゲット型で表現可能な場合、その値が使用される
  • それ以外の場合、動作は未定義となる。
int n = 3.14; // n == 3
int x = 1e10; // 32ビットintでは未定義動作

任意の整数型の値は、任意の実浮動小数点型に暗黙的に変換できます。

  • 値がターゲット型で正確に表現できる場合、その値は変更されません。
  • 値が表現可能だが正確に表現できない場合、結果は実装定義で最も近い上位値または最も近い下位値のいずれかが選択されます(ただしIEEE演算がサポートされている場合は最近接偶数丸めが行われます)。この場合に FE_INEXACT が発生するかどうかは未規定です。
  • 値が表現できない場合、動作は未定義ですが、IEEE演算がサポートされている場合は FE_INVALID が発生し、結果の値は未規定となります。

この変換の結果は、対象の型が示す範囲と精度を超える可能性があります( FLT_EVAL_METHOD を参照)。

浮動小数点から整数への変換において FE_INEXACT の制御が必要な場合、 rint および nearbyint を使用することができます。

double d = 10; // d = 10.00
float f = 20000001; // f = 20000000.00 (FE_INEXACT)
float x = 1 + (long long)FLT_MAX; // 未定義動作

実浮動小数点変換

任意の実浮動小数点型の値は、他の任意の実浮動小数点型に暗黙的に変換できます。

  • 値がターゲット型で正確に表現できる場合、その値は変更されません。
  • 値が表現可能だが正確に表現できない場合、結果は最も近い上位値または最も近い下位値になります(つまり、丸め方向は実装定義です)。ただし、IEEE演算がサポートされている場合は最近接丸めが行われます。
  • 値が表現できない場合、動作は未定義です

この変換の結果は、対象の型が示す範囲と精度を超える可能性があります( FLT_EVAL_METHOD を参照)。

double d = 0.1; // d = 0.1000000000000000055511151231257827021181583404541015625
float f = d;    // f = 0.100000001490116119384765625
float x = 2 * (double)FLT_MAX; // 未定義動作

複素数型変換

任意の複素数型の値は、他の任意の複素数型に暗黙的に変換できます。実数部と虚数部はそれぞれ、実浮動小数点型の変換規則に従います。

double complex d = 0.1 + 0.1*I;
float complex f = d; // f is (0.100000001490116119384765625, 0.100000001490116119384765625)

虚数型変換

任意の虚数型の値は、他の任意の虚数型に暗黙的に変換できます。虚数部は実浮動小数点型の変換規則に従います。

double imaginary d = 0.1*_Imaginary_I;
float imaginary f = d; // f is 0.100000001490116119384765625*I

実数-複素数変換

任意の実浮動小数点型の値は、任意の複素数型に暗黙的に変換できます。

  • 結果の実数部は、実浮動小数点型の変換規則によって決定されます。
  • 結果の虚数部は正のゼロ(非IEEEシステムでは符号なしゼロ)になります。

任意の複素数型の値は、任意の実浮動小数点型に暗黙的に変換できます。

  • 実数部は実浮動小数点型の規則に従って変換されます。
  • 虚数部は破棄されます。

注記:複素数から実数への変換では、虚数部のNaNは実数結果に伝播しません。

double complex z = 0.5 + 3*I;
float f = z;  // the imaginary part is discarded, f is set to 0.5
z = f;        // sets z to 0.5 + 0*I

実数-虚数変換

任意の虚数型の値は、任意の実数型(整数または浮動小数点)に暗黙的に変換できます。結果は常に正(または符号なし)のゼロになりますが、対象型が _Bool (C23まで) bool (C23以降) の場合はブール変換規則が適用されます。

任意の実数型の値は、任意の虚数型に暗黙的に変換できます。結果は常に正の虚数ゼロになります。

double imaginary z = 3*I;
bool b = z;  // Boolean conversion: sets b to true 
float f = z; // Real-imaginary conversion: sets f to 0.0 
z = 3.14;    // Imaginary-real conversion: sets z to 0*_Imaginary_I

複素数-虚数変換

任意の虚数型の値は、任意の複素数型に暗黙的に変換できます。

  • 結果の実数部は正のゼロになります。
  • 結果の虚数部は対応する実数型の変換規則に従います。

任意の複素数型の値は、任意の虚数型に暗黙的に変換できます。

  • 実数部は破棄されます。
  • 結果の虚数部は対応する実数型の変換規則に従います。
double imaginary z = I * (3*I); // the complex result -3.0+0i loses real part
                                // sets z to 0*_Imaginary_I
(C99以降)

ポインタ変換

任意のオブジェクト型へのポインタは、以下のセマンティクスで void ポインタとの間で暗黙的に変換できます:

  • オブジェクトへのポインタがvoidへのポインタに変換され、その後元に戻された場合、その値は元のポインタと等しいと比較されます。
  • その他の保証は提供されません。
int* p = malloc(10 * sizeof(int)); // mallocはvoid*を返す

修飾されていない型へのポインタは、その型の修飾されたバージョンへのポインタに暗黙的に変換できます(言い換えれば、 const volatile 、および restrict 修飾子を追加できます)。元のポインタと結果のポインタは等価と比較されます。

int n;
const int* p = &n; // &n は int* 型を持つ

値が 0 である任意の整数 定数式 および、型 void * にキャストされた値ゼロの整数ポインタ式は、任意のポインタ型(オブジェクトへのポインタと関数へのポインタの両方)に暗黙的に変換できます。結果はその型のヌルポインタ値となり、その型の非ヌルポインタ値とは等しくないことが保証されます。この整数または void * 式は ヌルポインタ定数 として知られ、標準ライブラリはこの定数の定義をマクロ NULL として提供しています。

int* p = 0;
double* q = NULL;

注記

符号付き整数のオーバーフローは算術演算子では未定義動作ですが、整数変換における符号付き整数型のオーバーフローは単なる未規定動作です。

一方で、算術演算子(および整数変換)における符号なし整数のオーバーフローは明確に定義された操作であり、モジュロ演算の規則に従いますが、浮動小数点から整数への変換における符号なし整数のオーバーフローは未定義動作です:符号なし整数に変換可能な実浮動小数点型の値は、開区間 ( -1 , Unnn_MAX + 1 ) の値です。

unsigned int n = -1.0; // 未定義動作

ポインタと整数の間の変換( ポインタから _Bool (C23まで) bool (C23以降) への変換と、 (C99以降) 値ゼロの整数定数式からポインタへの変換を除く)、オブジェクトへのポインタ間の変換(どちらかがvoidへのポインタの場合を除く)、および関数へのポインタ間の変換(関数が互換性のある型を持つ場合を除く)は、決して暗黙的には行われず、 キャスト演算子 を必要とします。

**翻訳のポイント:** - HTMLタグと属性は完全に保持 - ` `, `
`, ``タグ内のテキストは翻訳対象外(今回は該当なし)
- C++専門用語(_Bool, bool, cast operatorなど)は翻訳せず保持
- 技術文書としての正確性と専門性を維持
- 括弧内のバージョン表記は「(until C23)」→「(C23まで)」、「(since C23)」→「(C23以降)」と自然な日本語に変換
- 文法的に自然な日本語になるよう語順を調整

関数ポインタとオブジェクトへのポインタ( void * を含む)または整数との間には、(暗黙的または明示的な)変換は存在しません。

参考文献

  • C23規格 (ISO/IEC 9899:2024):
  • 6.3 変換 (p: 44-50)
  • C17規格(ISO/IEC 9899:2018):
  • 6.3 変換(ページ: 37-41)
  • C11規格 (ISO/IEC 9899:2011):
  • 6.3 変換 (p: 50-56)
  • C99規格 (ISO/IEC 9899:1999):
  • 6.3 変換 (p: 42-48)
  • C89/C90標準 (ISO/IEC 9899:1990):
  • 3.2 変換

関連項目

C++ ドキュメント for 暗黙の型変換