Namespaces
Variants

reinterpret_cast conversion

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

基礎となるビットパターンを再解釈することで型間の変換を行います。

目次

翻訳のポイント: - 「Contents」→「目次」に翻訳 - HTMLタグ、属性、
タグ内のテキストは翻訳せず保持
- C++固有の用語(Syntax、Explanation、Type aliasing、Type accessibility、Call compatibility、Notes、Keywords、Example、Defect reports、References、See also)は翻訳せず保持
- 元のフォーマットと構造を完全に維持

構文

reinterpret_cast< target-type >( expression )

target-type 型の値を返します。

説明

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

以下の変換のみが reinterpret_cast によって実行可能です。ただし、そのような変換が const性の除去 (またはvolatile性の除去)となる場合は除きます。

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

すべてのキャスト式と同様に、結果は次のとおりです:

  • target-type が左辺値参照型の場合(または関数型への右辺値参照型の場合 (C++11以降) )、左辺値となる;
  • target-type がオブジェクト型への右辺値参照の場合、xvalueとなる;
(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

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)
ある型のオブジェクト表現を別の型として再解釈
(関数テンプレート)