reinterpret_cast 変換
基になるビットパターンを再解釈することによって型間で変換します。
目次 |
[編集] 構文
reinterpret_cast< target-type >( expression ) |
|||||||||
ターゲット型の値を返します。
[編集] 説明
static_cast とは異なり、const_cast と同様に、reinterpret_cast 式は、CPU 命令にコンパイルされません(整数とポインタの間、またはポインタの表現が型に依存する特殊なアーキテクチャでポインタ間で変換する場合を除く)。これは主に、コンパイラに expression を target-type 型であるかのように扱うよう指示するコンパイル時ディレクティブです。
reinterpret_cast で行えるのは以下の変換のみです。ただし、そのような変換が constness (または volatility) を取り除く場合を除きます。
static_cast または 暗黙的な変換 を使用すべきです。|
4) nullptr を含む std::nullptr_t 型の任意の値を、まるで (void*)0 であるかのように任意の整数型に変換できます。ただし、nullptr でさえも std::nullptr_t に変換することはできません。この目的には static_cast を使用すべきです。
|
(C++11以降) |
T1* を別のオブジェクトポインタ型 cv T2* に変換できます。これは static_cast<cv T2*>(static_cast<cv void*>(expression)) とまったく同じです(つまり、T2 のアライメント要件が T1 のアライメント要件よりも厳しくない場合、ポインタの値は変更されず、結果のポインタを元の型に変換し直すと元の値が得られます)。いずれの場合も、結果のポインタは、逆参照される値が 型アクセシブル である場合にのみ安全に逆参照できます。T1 型の lvalue(C++11まで)glvalue(C++11以降) 式を別の型 T2 への参照に変換できます。結果は *reinterpret_cast<T2*>(p) であり、ここで p は expression で指定されたオブジェクトまたは関数への「T1 へのポインタ」型のポインタです。一時オブジェクトは 具体化されたり(C++17以降)作成されたりせず、コピーも行われず、コンストラクタや変換関数も呼び出されません。結果の参照は、それが 型アクセシブル である場合にのみ安全にアクセスできます。dlsym が要求する任意の POSIX 互換システムでは)、関数ポインタを void* または他の任意のオブジェクトポインタに、またはその逆に変換できます。実装が両方向の変換をサポートしている場合、元の型への変換は元の値を与え、それ以外の場合、結果のポインタは安全に逆参照または呼び出しできません。T1 のメンバオブジェクトへのポインタは、別のクラス T2 の別のメンバオブジェクトへのポインタに変換できます。T2 のアライメントが T1 のアライメントよりも厳しくない場合、元の型 T1 に戻す変換は元の値を与え、それ以外の場合、結果のポインタは安全に使用できません。すべてのキャスト式と同様に、結果は次のようになります。
- ターゲット型がlvalue参照型である場合、または関数型へのrvalue参照である場合、lvalueになります (C++11以降)。
|
(C++11以降) |
- それ以外の場合はprvalueになります。
[編集] 型エイリアシング
[編集] 型アクセシビリティ
型 T_ref が以下のいずれかの型と 類似 している場合、動的型 T_obj のオブジェクトは、T_ref 型の lvalue(C++11まで)glvalue(C++11以降) を介して型アクセシブルです。
- char
- unsigned char
|
(C++17以降) |
-
T_obj T_objに対応する符号付きまたは符号なし型
プログラムが、型アクセシブルではない lvalue(C++11まで)glvalue(C++11以降) を介してオブジェクトの保存された値を読み取ったり変更しようとすると、その動作は未定義です。
この規則により、型ベースのエイリアス解析が可能になります。この解析では、コンパイラは、ある型の glvalue を介して読み取られた値が、異なる型の glvalue への書き込みによって変更されないと仮定します(上記の例外に従います)。
多くの C++ コンパイラは、非標準の言語拡張として、共用体 の非アクティブなメンバを介した間違った型へのアクセスを許可するために、この規則を緩和することに注意してください(そのようなアクセスは C では未定義ではありません)。
[編集] 呼び出し互換性
以下の条件のいずれかが満たされる場合、型 T_call は関数型 T_func と呼び出し互換です。
-
T_callはT_funcと同じ型です。
|
(C++17以降) |
呼び出された関数の定義の型と呼び出し互換ではない 関数型 の式を介して関数が呼び出されると、その動作は未定義です。
[編集] 備考
アライメント要件が満たされていると仮定すると、reinterpret_cast は、ポインタ相互変換可能なオブジェクトを扱ういくつかの限られたケースを除いて、ポインタの値 を変更しません。
struct S1 { int a; } s1; struct S2 { int a; private: int b; } s2; // not standard-layout union U { int a; double b; } u = {0}; int arr[2]; int* p1 = reinterpret_cast<int*>(&s1); // value of p1 is "pointer to s1.a" because // s1.a and s1 are pointer-interconvertible int* p2 = reinterpret_cast<int*>(&s2); // value of p2 is unchanged by reinterpret_cast // and is "pointer to s2". int* p3 = reinterpret_cast<int*>(&u); // value of p3 is "pointer to u.a": // u.a and u are pointer-interconvertible double* p4 = reinterpret_cast<double*>(p3); // value of p4 is "pointer to u.b": u.a and // u.b are pointer-interconvertible because // both are pointer-interconvertible with u int* p5 = reinterpret_cast<int*>(&arr); // value of p5 is unchanged by reinterpret_cast // and is "pointer to arr"
適切な型のオブジェクトを実際に指定しない glvalue(例えば、reinterpret_cast を通して得られたもの)に対して、非静的データメンバまたは非静的メンバ関数を指定するクラスメンバアクセスを実行すると、未定義動作になります。
struct S { int x; }; struct T { int x; int f(); }; struct S1 : S {}; // standard-layout struct ST : S, T {}; // not standard-layout S s = {}; auto p = reinterpret_cast<T*>(&s); // value of p is "pointer to s" auto i = p->x; // class member access expression is undefined behavior; // s is not a T object p->x = 1; // undefined behavior p->f(); // undefined behavior S1 s1 = {}; auto p1 = reinterpret_cast<S*>(&s1); // value of p1 is "pointer to the S subobject of s1" auto i = p1->x; // OK p1->x = 1; // OK ST st = {}; auto p2 = reinterpret_cast<S*>(&st); // value of p2 is "pointer to st" auto i = p2->x; // undefined behavior p2->x = 1; // undefined behavior
多くのコンパイラは、このような場合に「厳密なエイリアシング」警告を発行します。技術的には、そのような構造は一般に「厳密なエイリアシング規則」として知られている段落以外のものに違反していますが。
厳密なエイリアシングと関連する規則の目的は、型ベースのエイリアス解析を可能にすることです。もしプログラムが無関係な型(例:int* と float*)への2つのポインタが同時に存在し、両方が同じメモリをロードまたはストアするために使用できる状況を有効に作成できる場合、この解析は壊れてしまいます(SG12 リフレクタ上のこのメール を参照)。したがって、そのような状況を作成できると思われるいかなるテクニックも、必然的に未定義動作を引き起こします。
オブジェクトのバイトを異なる型の値として解釈する必要がある場合、std::memcpy または std::bit_cast(C++20以降) を使用できます。
double d = 0.1; std::int64_t n; static_assert(sizeof n == sizeof d); // n = *reinterpret_cast<std::int64_t*>(&d); // Undefined behavior std::memcpy(&n, &d, sizeof d); // OK n = std::bit_cast<std::int64_t>(d); // also OK
|
実装が std::intptr_t および/または std::uintptr_t を提供する場合、オブジェクト型または cv void へのポインタからこれらの型へのキャストは常に適切に定義されます。ただし、これは関数ポインタには保証されません。 |
(C++11以降) |
Cでは、集合体のコピーと代入は集合体オブジェクト全体にアクセスします。しかし、C++ではそのような操作は常にメンバ関数呼び出しを介して実行され、オブジェクト全体ではなく個々のサブオブジェクトにアクセスします(または、共用体の場合、オブジェクト表現をコピーします。つまり、unsigned char を介して)。
[編集] キーワード
[編集] 例
reinterpret_cast のいくつかの使用法を示します。
#include <cassert> #include <cstdint> #include <iostream> int f() { return 42; } int main() { int i = 7; // pointer to integer and back std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast is an error std::cout << "The value of &i is " << std::showbase << std::hex << v1 << '\n'; int* p1 = reinterpret_cast<int*>(v1); assert(p1 == &i); // pointer to function to another and back void(*fp1)() = reinterpret_cast<void(*)()>(f); // fp1(); undefined behavior int(*fp2)() = reinterpret_cast<int(*)()>(fp1); std::cout << std::dec << fp2() << '\n'; // safe // type aliasing through pointer char* p2 = reinterpret_cast<char*>(&i); std::cout << (p2[0] == '\x7' ? "This system is little-endian\n" : "This system is big-endian\n"); // type aliasing through reference reinterpret_cast<unsigned int&>(i) = 42; std::cout << i << '\n'; [[maybe_unused]] const int &const_iref = i; // int &iref = reinterpret_cast<int&>( // const_iref); // compiler error - can't get rid of const // Must use const_cast instead: int &iref = const_cast<int&>(const_iref); }
実行結果の例
The value of &i is 0x7fff352c3580 42 This system is little-endian 42
[編集] 欠陥報告
以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。
| DR | 適用対象 | 公開された動作 | 正しい動作 |
|---|---|---|---|
| CWG 195 | C++98 | 関数ポインタ間の変換 およびオブジェクトポインタは許可されない |
条件付きサポートとされた |
| CWG 658 | C++98 | ポインタ変換の結果は未指定だった (元の型に戻す変換を除く) |
ポインタの仕様が提供された その指す型が アライメント要件を満たす |
| CWG 799 | C++98 | どの同一性変換が reinterpret_cast で行えるか不明だった |
明確化された |
| CWG 1268 | C++11 | reinterpret_cast は lvalue を参照型にしかキャストできなかった |
xvalue も許可された |
| CWG 2780 | C++98 | reinterpret_cast は 関数 lvalue を他の参照型にキャストできなかった |
許可 |
| CWG 2939 | C++17 | reinterpret_cast は prvalue を右辺値参照型にキャストできた |
許可されなくなった。 |
[編集] 参照
- C++23標準 (ISO/IEC 14882:2024)
- 7.6.1.10 再解釈キャスト [expr.reinterpret.cast]
- C++20 standard (ISO/IEC 14882:2020)
- 7.6.1.9 再解釈キャスト [expr.reinterpret.cast]
- C++17 standard (ISO/IEC 14882:2017)
- 8.2.10 再解釈キャスト [expr.reinterpret.cast]
- C++14 standard (ISO/IEC 14882:2014)
- 5.2.10 再解釈キャスト [expr.reinterpret.cast]
- C++11 standard (ISO/IEC 14882:2011)
- 5.2.10 再解釈キャスト [expr.reinterpret.cast]
- C++98 標準 (ISO/IEC 14882:1998)
- 5.2.10 再解釈キャスト [expr.reinterpret.cast]
- C++03 標準 (ISO/IEC 14882:2003)
- 5.2.10 再解釈キャスト [expr.reinterpret.cast]
[編集] 関連項目
const_cast 変換
|
const を追加または削除します |
static_cast 変換
|
基本的な変換を実行します |
dynamic_cast 変換
|
チェックされた多態的な変換を実行します |
| 明示的キャスト | 型間の許容される変換 |
| 標準変換 | ある型から別の型への暗黙的な変換 |
| (C++20) |
ある型のオブジェクト表現を別の型のオブジェクト表現として再解釈する (関数テンプレート) |