Implicit conversions
式が異なる型の値が期待される文脈で使用される場合、 変換 が発生することがあります:
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
整数型の各引数は 整数昇格 を受け、 float 型の各引数は暗黙的に double 型に変換されます。
int add_nums(int count, ...); int sum = add_nums(2, 'c', true); // add_numsは3つのintで呼び出される: (2, 99, 1)
|
|
(C99以降) |
通常の算術変換
以下の算術演算子の引数は、 共通実数型 を取得するために暗黙の型変換を受けます。これは計算が実行される型です:
|
1)
一方のオペランドが十進浮動小数点型の場合、他方のオペランドは標準浮動小数点型、
複素数型、または虚数型であってはならない。
|
(C23以降) |
-
- 整数型または実浮動小数点型は long double に変換
| (C99以降) |
-
- 整数型または実浮動小数点型は double に変換
| (C99以降) |
-
- 整数型は float に変換(実数型で可能なのはfloatのみであり、その場合はそのまま維持)
| (C99以降) |
-
- 型が同じ場合、その型が共通型となる。
- それ以外の場合、型が異なる:
- ↑ ランク付けの規則については以下の 整数プロモーション を参照。
- ↑ 以下の 暗黙的変換セマンティクス の「整数変換」を参照。
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)
|
結果の型は以下のように決定されます:
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変換
任意の非配列型の 左辺値式 は、以下のいずれでもない文脈で使用される場合
- アドレス取得演算子 の被演算子として(許可される場合)、
- 前置/後置 インクリメントおよびデクリメント演算子 の被演算子として、
- メンバアクセス (ドット)演算子の左側被演算子として、
- 代入および複合代入 演算子の左側被演算子として、
-
sizeofの被演算子として、
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以降) で 配列型 のものは、以下の文脈以外で使用される場合
- アドレス取得演算子 の被演算子として、
-
sizeofの被演算子として、 -
typeofおよびtypeof_unqual(C23以降) の被演算子として、 - 配列初期化 で使用される文字列リテラルとして、
その配列の最初の要素を指す非左値ポインタへの変換を受けます。
配列が
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; }
関数からポインタへの変換
関数指示子式は、以下のいずれかの文脈以外で使用される場合、
- アドレス取得演算子 の被演算子として、
-
sizeofの被演算子として、 -
typeofおよびtypeof_unqual(C23以降) の被演算子として、
式によって指定される関数への非左値ポインタへの変換が行われます。
int f(int); int (*p)(int) = f; // fへの変換 (***p)(1); // fへの繰り返し逆参照と&fへの変換
暗黙的変換セマンティクス
暗黙の変換は、 as if by assignment または usual arithmetic conversion のいずれであっても、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 の特性であり、以下のように定義されます:
|
8)
ビット精度符号付き整数型の順位は、より小さい幅を持つ任意の標準整数型またはより小さい幅を持つ任意のビット精度整数型の順位よりも大きくなければならない。
9)
同じ幅を持つ拡張整数型に対する任意のビット精度整数型の順位は実装定義である。
|
(C23以降) |
注:整数プロモーションは以下の場合にのみ適用されます
- 通常の算術変換の一部として(上記参照)、
- デフォルト引数プロモーションの一部として(上記参照)、
- 単項算術演算子 + および - のオペランドに対して、
- 単項ビット演算子 ~ のオペランドに対して、
- シフト演算子 << および >> の両方のオペランドに対して。
ブーリアン変換任意のスカラー型の値は暗黙的に _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演算がサポートされている場合は最近接丸めが行われます。
-
値が表現できない場合、動作は未定義です
。このセクションは不完全です
理由:適切に符号付けされた無限大が必要かどうかIEEEを確認
この変換の結果は、対象の型が示す範囲と精度を超える可能性があります( FLT_EVAL_METHOD を参照)。
double d = 0.1; // d = 0.1000000000000000055511151231257827021181583404541015625 float f = d; // f = 0.100000001490116119384765625 float x = 2 * (double)FLT_MAX; // 未定義動作
複素数型変換任意の複素数型の値は、他の任意の複素数型に暗黙的に変換できます。実数部と虚数部はそれぞれ、実浮動小数点型の変換規則に従います。 虚数型変換任意の虚数型の値は、他の任意の虚数型に暗黙的に変換できます。虚数部は実浮動小数点型の変換規則に従います。 double imaginary d = 0.1*_Imaginary_I; float imaginary f = d; // f is 0.100000001490116119384765625*I 実数-複素数変換任意の実浮動小数点型の値は、任意の複素数型に暗黙的に変換できます。
任意の複素数型の値は、任意の実浮動小数点型に暗黙的に変換できます。
注記:複素数から実数への変換では、虚数部の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タグと属性は完全に保持 - `
`, `
`, `
関数ポインタとオブジェクトへのポインタ( 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
暗黙の型変換
|