名前空間
変種
操作

reinterpret_cast 変換

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

基になるビットパターンを再解釈することによって型間で変換します。

目次

[編集] 構文

reinterpret_cast< target-type >( expression )

ターゲット型の値を返します。

[編集] 説明

static_cast とは異なり、const_cast と同様に、reinterpret_cast 式は、CPU 命令にコンパイルされません(整数とポインタの間、またはポインタの表現が型に依存する特殊なアーキテクチャでポインタ間で変換する場合を除く)。これは主に、コンパイラに expressiontarget-type 型であるかのように扱うよう指示するコンパイル時ディレクティブです。

reinterpret_cast で行えるのは以下の変換のみです。ただし、そのような変換が constness (または volatility) を取り除く場合を除きます。

1) 整数型、列挙型、ポインタ型、またはメンバポインタ型の式を自身の型に変換できます。結果の値は expression の値と同じです。
2) ポインタは、その型のすべての値を保持できる十分な大きさの任意の整数型(例: std::uintptr_t)に変換できます。
3) 任意の整数型または列挙型の値をポインタ型に変換できます。十分な大きさの整数に変換され、同じポインタ型に戻されたポインタは、元の値を持つことが保証されます。それ以外の場合、結果のポインタは安全に逆参照できません(逆方向の往復変換は保証されません。同じポインタが複数の整数表現を持つ可能性があります)。ヌルポインタ定数 NULL または整数ゼロは、ターゲット型のヌルポインタ値を生成することを保証されません。この目的には static_cast または 暗黙的な変換 を使用すべきです。
4) nullptr を含む std::nullptr_t 型の任意の値を、まるで (void*)0 であるかのように任意の整数型に変換できます。ただし、nullptr でさえも std::nullptr_t に変換することはできません。この目的には static_cast を使用すべきです。
(C++11以降)
5) 任意のオブジェクトポインタ型 T1* を別のオブジェクトポインタ型 cv T2* に変換できます。これは static_cast<cv T2*>(static_cast<cv void*>(expression)) とまったく同じです(つまり、T2 のアライメント要件が T1 のアライメント要件よりも厳しくない場合、ポインタの値は変更されず、結果のポインタを元の型に変換し直すと元の値が得られます)。いずれの場合も、結果のポインタは、逆参照される値が 型アクセシブル である場合にのみ安全に逆参照できます。
6) T1 型の lvalue(C++11まで)glvalue(C++11以降) 式を別の型 T2 への参照に変換できます。結果は *reinterpret_cast<T2*>(p) であり、ここで pexpression で指定されたオブジェクトまたは関数への「T1 へのポインタ」型のポインタです。一時オブジェクトは 具体化されたり(C++17以降)作成されたりせず、コピーも行われず、コンストラクタや変換関数も呼び出されません。結果の参照は、それが 型アクセシブル である場合にのみ安全にアクセスできます。
7) 任意の関数ポインタを別の関数型へのポインタに変換できます。結果は未指定ですが、そのようなポインタを元の関数型へのポインタに戻すと、元の関数へのポインタが得られます。結果のポインタは、その関数型が元の関数型と 呼び出し互換 である場合にのみ安全に呼び出すことができます。
8) 一部の実装では(特に、dlsym が要求する任意の POSIX 互換システムでは)、関数ポインタを void* または他の任意のオブジェクトポインタに、またはその逆に変換できます。実装が両方向の変換をサポートしている場合、元の型への変換は元の値を与え、それ以外の場合、結果のポインタは安全に逆参照または呼び出しできません。
9) 任意のポインタ型のヌルポインタ値は、他の任意のポインタ型に変換でき、その型のヌルポインタ値になります。ヌルポインタ定数 nullptr または std::nullptr_t 型の他の任意の値を reinterpret_cast でポインタに変換できないことに注意してください。この目的には、暗黙的な変換または static_cast を使用すべきです。
10) メンバ関数へのポインタは、異なる型の異なるメンバ関数へのポインタに変換できます。元の型に戻す変換は元の値を与え、それ以外の場合、結果のポインタは安全に使用できません。
11) あるクラス T1 のメンバオブジェクトへのポインタは、別のクラス T2 の別のメンバオブジェクトへのポインタに変換できます。T2 のアライメントが T1 のアライメントよりも厳しくない場合、元の型 T1 に戻す変換は元の値を与え、それ以外の場合、結果のポインタは安全に使用できません。

すべてのキャスト式と同様に、結果は次のようになります。

  • ターゲット型がlvalue参照型である場合、または関数型へのrvalue参照である場合、lvalueになります (C++11以降)
  • ターゲット型がオブジェクト型へのrvalue参照である場合、xvalueになります。
(C++11以降)
  • それ以外の場合はprvalueになります。

[編集] 型エイリアシング

[編集] 型アクセシビリティ

T_ref が以下のいずれかの型と 類似 している場合、動的型 T_obj のオブジェクトは、T_ref 型の lvalue(C++11まで)glvalue(C++11以降) を介して型アクセシブルです。

  • char
  • unsigned char
  • std::byte
(C++17以降)
  • T_obj
  • T_obj に対応する符号付きまたは符号なし型

プログラムが、型アクセシブルではない lvalue(C++11まで)glvalue(C++11以降) を介してオブジェクトの保存された値を読み取ったり変更しようとすると、その動作は未定義です。

この規則により、型ベースのエイリアス解析が可能になります。この解析では、コンパイラは、ある型の glvalue を介して読み取られた値が、異なる型の glvalue への書き込みによって変更されないと仮定します(上記の例外に従います)。

多くの C++ コンパイラは、非標準の言語拡張として、共用体 の非アクティブなメンバを介した間違った型へのアクセスを許可するために、この規則を緩和することに注意してください(そのようなアクセスは C では未定義ではありません)。

[編集] 呼び出し互換性

以下の条件のいずれかが満たされる場合、型 T_call は関数型 T_func呼び出し互換です。

  • T_callT_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

[編集]

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)
ある型のオブジェクト表現を別の型のオブジェクト表現として再解釈する
(関数テンプレート) [編集]
English 日本語 中文(简体) 中文(繁體)