reinterpret_cast
轉換
透過重新解釋底層位模式在型別之間進行轉換。
目錄 |
[編輯] 語法
reinterpret_cast< 目標型別 >( 表示式 ) |
|||||||||
返回 目標型別 的值。
[編輯] 解釋
與 static_cast 不同,但與 const_cast 類似,reinterpret_cast 表示式不會編譯成任何 CPU 指令(除非在整數和指標之間轉換,或者在某些指標表示取決於其型別的晦澀架構上轉換指標)。它主要是一個編譯時指令,指示編譯器將 表示式 視為具有 目標型別。
只有以下轉換可以使用 reinterpret_cast 完成,除非此類轉換會去除 constness(或 volatility)。
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*>(表示式))(這意味著如果 T2
的對齊要求不比 T1
嚴格,則指標的值不會改變,並且將結果指標轉換回其原始型別會產生原始值)。在任何情況下,只有當解引用的值是型別可訪問時,結果指標才能安全地解引用。T1
的左值(C++11前)泛左值(C++11起)表示式可以轉換為對另一種型別 T2
的引用。結果是 *reinterpret_cast<T2*>(p),其中 p 是指向 表示式 指定的物件或函式的“指向 T1
的指標”型別的指標。不實現或(C++17起)建立臨時物件,不進行復制,不呼叫建構函式或轉換函式。只有當結果引用是型別可訪問時,才能安全地訪問它。dlsym
所要求),函式指標可以轉換為 void* 或任何其他物件指標,反之亦然。如果實現支援雙向轉換,則轉換為原始型別會產生原始值,否則結果指標不能安全地解引用或呼叫。T1
的成員物件的指標可以轉換為指向另一個類 T2
的另一個成員物件的指標。如果 T2
的對齊不比 T1
嚴格,則轉換回原始型別 T1
會產生原始值,否則結果指標不能安全使用。與所有轉換表示式一樣,結果是
- 如果 目標型別 是左值引用型別或函式型別的右值引用(C++11 起),則為左值;
|
(C++11 起) |
- 否則為純右值。
[編輯] 類型別名
[編輯] 型別可訪問性
如果型別 T_ref
與以下任何型別相似,則透過型別為 T_ref
的左值(C++11前)泛左值(C++11起)可以型別可訪問動態型別為 T_obj
的物件:
- char
- unsigned char
|
(C++17 起) |
-
T_obj
- 與
T_obj
對應的有符號或無符號型別
如果程式試圖透過其不可型別訪問的左值(C++11前)泛左值(C++11起)讀取或修改物件的儲存值,則行為未定義。
此規則支援基於型別的別名分析,其中編譯器假設透過一種型別的泛左值讀取的值不會被寫入不同型別的泛左值所修改(受上述例外情況的約束)。
請注意,許多 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"
對實際不指定適當型別物件(例如透過 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*)同時存在並且都可以用於載入或儲存相同記憶體的情況,那麼這種分析就會被破壞(參見 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++ 標準。
缺陷報告 | 應用於 | 釋出時的行為 | 正確的行為 |
---|---|---|---|
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 Reinterpret cast [expr.reinterpret.cast]
- C++20 標準 (ISO/IEC 14882:2020)
- 7.6.1.9 Reinterpret cast [expr.reinterpret.cast]
- C++17 標準 (ISO/IEC 14882:2017)
- 8.2.10 Reinterpret cast [expr.reinterpret.cast]
- C++14 標準 (ISO/IEC 14882:2014)
- 5.2.10 Reinterpret cast [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 Reinterpret cast [expr.reinterpret.cast]
- C++03 標準 (ISO/IEC 14882:2003)
- 5.2.10 Reinterpret cast [expr.reinterpret.cast]
[編輯] 另請參閱
const_cast 轉換
|
新增或刪除 const |
static_cast 轉換
|
執行基本轉換 |
dynamic_cast 轉換
|
執行檢查的多型轉換 |
顯式轉換 | 型別之間的寬容轉換 |
標準轉換 | 從一種型別到另一種型別的隱式轉換 |
(C++20) |
將一種型別的物件表示重新解釋為另一種型別的物件表示 (函式模板) |