reinterpret_cast
conversion
基礎となるビットパターンを再解釈することで型間の変換を行います。
目次 |
、
、
構文
reinterpret_cast<
target-type
>(
expression
)
|
|||||||||
target-type 型の値を返します。
説明
static_cast とは異なりますが、 const_cast と同様に、 reinterpret_cast 式は(整数とポインタの変換、あるいはポインタの表現がその型に依存する特殊なアーキテクチャにおけるポインタ間の変換を除き)CPU命令にコンパイルされません。これは主に、 expression を target-type 型であるかのように扱うようコンパイラに指示するコンパイル時ディレクティブです。
以下の変換のみが reinterpret_cast によって実行可能です。ただし、そのような変換が const性の除去 (またはvolatile性の除去)となる場合は除きます。
static_cast
または
暗黙変換
を使用する必要があります。
|
4)
std::nullptr_t
型の任意の値(
nullptr
を含む)は、
(
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
は「
T1
へのポインタ」型のポインタで、
expression
によって指定されるオブジェクトまたは関数を指す。一時オブジェクトは
具体化されず
(C++17以降)
、コピーは作成されず、コンストラクタや変換関数は呼び出されない。結果の参照は、
型アクセス可能
である場合にのみ安全にアクセスできる。
dlsym
によって要求されるPOSIX互換システム)では、関数ポインタを
void
*
または他のオブジェクトポインタに変換可能、あるいはその逆も可能です。両方向の変換を実装がサポートする場合、元の型への変換は元の値を返します。そうでない場合、結果のポインタは安全にデリファレンスまたは呼び出しできません。
T1
のメンバオブジェクトへのポインタは、別のクラス
T2
の別のメンバオブジェクトへのポインタに変換できます。
T2
のアライメントが
T1
のアライメントよりも厳密でない場合、元の型
T1
への変換によって元の値が得られます。それ以外の場合、結果のポインタは安全に使用できません。
すべてのキャスト式と同様に、結果は次のとおりです:
- target-type が左辺値参照型の場合(または関数型への右辺値参照型の場合 (C++11以降) )、左辺値となる;
|
(since C++11) |
- それ以外の場合は prvalue。
型エイリアス
型アクセシビリティ
型
T_ref
が以下のいずれかの型に
similar
である場合、
dynamic type
T_obj
のオブジェクトは、
lvalue
(until C++11)
glvalue
(since C++11)
型
T_ref
の
type-accessible
となります:
- char 、 unsigned char または std::byte (C++17以降) :これにより、あらゆるオブジェクトの オブジェクト表現 をバイト配列として検査することが可能になります。
-
T_obj -
T_objに対応する符号付きまたは符号なしの型
プログラムが型アクセス可能でない lvalue (until C++11) glvalue (since C++11) を通じてオブジェクトの格納された値を読み取りまたは変更しようとする場合、その動作は未定義です。
このルールは型ベースのエイリアス解析を有効にします。これにより、コンパイラはある型のglvalueを通じて読み取られた値が、異なる型のglvalueへの書き込みによって変更されないと仮定します(前述の例外に従います)。
C++の多くのコンパイラは、非標準の言語拡張としてこの規則を緩和し、 union の非アクティブメンバーを通じた異なる型でのアクセスを許可することに注意してください(このようなアクセスはC言語では未定義動作ではありません)。
呼び出し互換性
以下のいずれかの条件が満たされる場合、型
T_call
は関数型
T_func
と
呼び出し互換性
があります:
-
T_callはT_funcと同じ型です。
|
(C++17以降) |
関数が、その function type が呼び出される関数の定義の型と呼び出し互換性がない式を通じて呼び出された場合、動作は未定義です。
注記
アライメント要件が満たされていると仮定すると、 reinterpret_cast は、 ポインタの値 を変更しません。ただし、 pointer-interconvertible オブジェクトに関わるいくつかの限定的なケースを除きます:
struct S1 { int a; } s1; struct S2 { int a; private: int b; } s2; // 標準レイアウトではない union U { int a; double b; } u = {0}; int arr[2]; int* p1 = reinterpret_cast<int*>(&s1); // p1の値は「s1.aへのポインタ」である // s1.aとs1はポインタ相互変換可能であるため int* p2 = reinterpret_cast<int*>(&s2); // p2の値はreinterpret_castによって変更されず // 「s2へのポインタ」のままである int* p3 = reinterpret_cast<int*>(&u); // p3の値は「u.aへのポインタ」である: // u.aとuはポインタ相互変換可能である double* p4 = reinterpret_cast<double*>(p3); // p4の値は「u.bへのポインタ」である:u.aと // u.bは両方ともuとポインタ相互変換可能であるため // 互いにポインタ相互変換可能である int* p5 = reinterpret_cast<int*>(&arr); // p5の値はreinterpret_castによって変更されず // 「arrへのポインタ」のままである
実際に適切な型のオブジェクトを指定していないglvalue(例えば reinterpret_cast を通じて取得されたものなど)に対して、非静的データメンバーまたは非静的メンバー関数を指定するクラスメンバーアクセスを実行すると、未定義動作が生じます:
struct S { int x; }; struct T { int x; int f(); }; struct S1 : S {}; // 標準レイアウト struct ST : S, T {}; // 標準レイアウトではない S s = {}; auto p = reinterpret_cast<T*>(&s); // pの値は「sへのポインタ」 auto i = p->x; // クラスメンバアクセス式は未定義動作; // sはTオブジェクトではない p->x = 1; // 未定義動作 p->f(); // 未定義動作 S1 s1 = {}; auto p1 = reinterpret_cast<S*>(&s1); // p1の値は「s1のSサブオブジェクトへのポインタ」 auto i = p1->x; // OK p1->x = 1; // OK ST st = {}; auto p2 = reinterpret_cast<S*>(&st); // p2の値は「stへのポインタ」 auto i = p2->x; // 未定義動作 p2->x = 1; // 未定義動作
多くのコンパイラはこのような場合に「strict aliasing」警告を発しますが、技術的にはそのような構造は一般に「strict aliasing rule」として知られる段落以外の何かに違反しているからです。
厳格なエイリアシングと関連する規則の目的は、型ベースのエイリアス解析を可能にすることです。もしプログラムが、無関係な型への2つのポインタ(例えば、 int * と float * )が同時に存在し、両方が同じメモリの読み書きに使用できる状況を有効に作成できる場合、この解析は崩壊します( 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); // 未定義動作 std::memcpy(&n, &d, sizeof d); // OK n = std::bit_cast<std::int64_t>(d); // こちらもOK
|
実装が std::intptr_t および/または std::uintptr_t を提供する場合、オブジェクト型または cv void へのポインタからこれらの型へのキャストは常に well-defined である。しかし、関数ポインタについてはこれは保証されない。 |
(C++11以降) |
Cでは、集約コピーと代入は集約オブジェクト全体にアクセスします。しかしC++では、そのような操作は常にメンバー関数呼び出しを通じて実行され、オブジェクト全体ではなく個々のサブオブジェクトにアクセスします(または、unionの場合にはオブジェクト表現をコピーします、すなわち unsigned char を通じて)。
キーワード
例
reinterpret_cast のいくつかの使用例を示します:
#include <cassert> #include <cstdint> #include <iostream> int f() { return 42; } int main() { int i = 7; // ポインタから整数へ、およびその逆 std::uintptr_t v1 = reinterpret_cast<std::uintptr_t>(&i); // static_cast はエラー std::cout << "The value of &i is " << std::showbase << std::hex << v1 << '\n'; int* p1 = reinterpret_cast<int*>(v1); assert(p1 == &i); // 関数ポインタから別の関数ポインタへ、およびその逆 void(*fp1)() = reinterpret_cast<void(*)()>(f); // fp1(); 未定義動作 int(*fp2)() = reinterpret_cast<int(*)()>(fp1); std::cout << std::dec << fp2() << '\n'; // 安全 // ポインタを通じた型エイリアシング char* p2 = reinterpret_cast<char*>(&i); std::cout << (p2[0] == '\x7' ? "This system is little-endian\n" : "This system is big-endian\n"); // 参照を通じた型エイリアシング reinterpret_cast<unsigned int&>(i) = 42; std::cout << i << '\n'; [[maybe_unused]] const int &const_iref = i; // int &iref = reinterpret_cast<int&>( // const_iref); // コンパイルエラー - const を除去できない // const_cast を使用する必要がある: 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
は左辺値のみ
参照型へキャスト可能であった |
亡値も許可 |
| CWG 2780 | C++98 |
reinterpret_cast
は関数左辺値を
他の参照型へキャストできなかった |
許可 |
| CWG 2939 | C++17 |
reinterpret_cast
は純粋右値を
右辺値参照型へキャスト可能であった |
許可されない |
参考文献
- C++23規格 (ISO/IEC 14882:2024):
-
- 7.6.1.10 再解釈キャスト [expr.reinterpret.cast]
- C++20 標準 (ISO/IEC 14882:2020):
-
- 7.6.1.9 リインタープリットキャスト [expr.reinterpret.cast]
- C++17 標準 (ISO/IEC 14882:2017):
-
- 8.2.10 リインタープリットキャスト [expr.reinterpret.cast]
- C++14 標準 (ISO/IEC 14882:2014):
-
- 5.2.10 再解釈キャスト [expr.reinterpret.cast]
- C++11標準 (ISO/IEC 14882:2011):
-
- 5.2.10 Reinterpret cast [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)
|
ある型のオブジェクト表現を別の型として再解釈
(関数テンプレート) |