簡體   English   中英

將 void* 轉換為任何內容時,我應該使用 static_cast 還是 reinterpret_cast

[英]Should I use static_cast or reinterpret_cast when casting a void* to whatever

static_castreinterpret_cast似乎都可以很好地將void*轉換為另一種指針類型。 有充分的理由偏愛其中之一嗎?

使用static_cast :它是最精確的演員,它准確地描述了在這里進行的轉換。

有一種誤解,即使用reinterpret_cast會更好地匹配,因為它意味着“完全忽略類型安全並且只是從A轉換為B”。

但是,這實際上並沒有描述reinterpret_cast的效果。 相反, reinterpret_cast有許多含義,因為所有這些含義都認為“ reinterpret_cast執行的映射是實現定義的。”[5.2.10.3]

但是在從void*T*的特定情況下,映射完全由標准定義; 即,在不改變其地址的情況下為無類型指針分配類型。

這是首選static_cast的原因。

此外,可以說更重要的是,每次使用reinterpret_cast都是非常危險的,因為它將任何東西轉換為其他任何東西(用於指針),而static_cast則更具限制性,從而提供更好的保護級別。 這已經讓我免於我偶然試圖將一個指針類型強制轉換為另一個指針類型的錯誤。

static_cast更適合將void*轉換為其他類型的指針。

當兩種類型之間存在自然、直觀的轉換但不一定保證在運行時工作時, static_cast是首選轉換。 例如,您可以使用static_cast將基類指針轉換為派生類指針,這種轉換在某些情況下是有意義的,但要到運行時才能驗證。 同樣,您可以使用static_castint轉換為char ,它定義明確,但在執行時可能會導致精度損失。

另一方面, reinterpret_cast是一個轉換運算符,旨在進行從根本上不安全或不可移植的轉換。 例如,您可以使用reinterpret_castvoid *轉換為int ,如果您的系統碰巧有sizeof (void*)sizeof (int) ,這將正常工作。 您還可以使用reinterpret_castfloat*轉換為int*或反之,這是特定於平台的,因為不能保證float s 和int s 的特定表示彼此有任何共同之處。

簡而言之,如果您發現自己進行的轉換在邏輯上有意義但在運行時可能不一定成功,請避免使用reinterpret_cast static_cast是一個不錯的選擇,如果你預先知道轉換將在運行時工作,並與編譯器通信“我知道這可能行不通,但至少它是有道理的,我有理由相信它會在運行時正確地做正確的事。” 然后編譯器可以檢查轉換是否在相關類型之間,如果不是這種情況則報告編譯時錯誤。 使用reinterpret_cast通過指針轉換來完成此操作完全繞過了編譯時安全檢查。

在某些情況下,您可能希望使用dynamic_cast而不是static_cast ,但這些情況大多涉及類層次結構中的強制轉換,並且(很少)直接涉及void*

至於規范更喜歡哪一個,都沒有被過度提及為“正確使用”(或者至少,我不記得其中一個被這樣提及。)但是,我認為規范希望你使用static_cast而不是reinterpret_cast 例如,當使用 C 風格的轉換時,如

A* ptr = (A*) myVoidPointer;

嘗試的轉換運算符的順序總是嘗試在reinterpret_cast之前使用static_cast ,這是您想要的行為,因為不能保證reinterpret_cast是可移植的。

這是一個棘手的問題。 一方面,Konrad對reinterpret_cast的規范定義提出了一個很好的觀點,盡管在實踐中它可能做同樣的事情。 另一方面,如果你在指針類型之間進行轉換(例如,當通過char *在內存中索引時相當常見), static_cast將生成編譯器錯誤,並且無論如何你將被迫使用reinterpret_cast

在實踐中我使用reinterpret_cast,因為它更能描述強制轉換操作的意圖。 您當然可以為不同的運算符設置一個僅指定指針重新解釋的情況(保證返回相同的地址),但標准中沒有一個。

您可能通過隱式轉換獲得了void* ,因此您應該使用static_cast ,因為它最接近隱式轉換。

使用static_cast和使用reinterpret_cast來回轉換void*是相同的。 請參閱鏈接中的答案。 但通常static_cast是首選,因為它更窄並且通常(但不是在這種特定情況下)更安全的轉換。

我建議總是使用最弱的演員。

reinterpret_cast可用於將指針強制轉換為float 演員陣容的結構越多,使用它就越需要關注。

char*情況下,我會使用c風格的強制轉換,直到我們有一些reinterpret_pointer_cast ,因為它更弱,沒有其他任何東西就足夠了。

為此使用static_cast 僅在極少數情況下沒有其他方法時使用reinterpret_cast

關於實現定義的映射存在混淆。 那是關於映射的。 實現可以按照自己喜歡的方式進行內部映射,但它必須以其他方式做出其他保證。 reinterpret_cast 的結果不能簡單地任意指向實現將考慮其他對象位置的內容——盡管外部表示可能不同。 (雖然轉換為整數並返回將具有原始值,但在特定情況下,會進行概述)。 從根本上說,實現的重新解釋的轉換是否返回相同的“內存位置”是無關緊要的; 它返回的任何內容都映射到相同的“值” (順便說一下, 核心指南明確回答了使用 reinterpret_cast (char*/unsigned char*/std::byte*) 查看原始對象表示是已定義行為的情況。)

相關標准規定 void* 投:

靜態投射

“指向 cv1 void 的指針”類型的純右值可以轉換為“指向 cv2 T 的指針”類型的純右值,其中 T 是一個對象類型,並且 cv2 與 cv1 具有相同的 cv 資格,或者比 cv1 更高的 cv 資格。 如果原來的指針值表示一個字節在內存中的地址A,A不滿足T的對齊要求,那么得到的指針值是未指定的。 否則,如果原始指針值指向一個對象 a,並且有一個類型為 T 的對象 b(忽略 cv 限定)與 a 指針可互換(6.8.3),則結果是指向 b 的指針。 否則,指針值不會因轉換而改變。 [示例 3: T* p1 = new T; const T* p2 = static_cast<const T*>(static_cast<void*>(p1)); bool b = p1 == p2; // b will have the value true. T* p1 = new T; const T* p2 = static_cast<const T*>(static_cast<void*>(p1)); bool b = p1 == p2; // b will have the value true. ——結束例子]

重新詮釋演員表

對象指針可以顯式轉換為不同類型的對象指針。68 當對象指針類型的純右值 v 轉換為對象指針類型“pointer to cv T”時,結果為static_cast<cv T*>(static_cast<cv void*>(v))

關鍵是最后一句。 出於這個問題的 void* 演員的目的,(並假設對象類型滿足對齊要求、cv 資格,並且是安全派生的指針):

來自 void* 的reinterpret_cast T* from void*static_cast T* from void*

但是你絕對應該絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對絕對使用static_cast沒有其他原因,因為關於 reinterpret_cast 的可怕民間傳說和 ISO 標准的復雜性可能會導致你被同行不必要地喋喋不休。

https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Ru-pun

reinterpret_cast將強制將void*轉換為目標數據類型。 它不保證任何安全,您的程序可能會崩潰,因為底層對象可能是任何東西。

例如,您可以將myclass*類型轉換為void* ,然后使用reinterpret_cast將其轉換為可能具有完全不同布局的yourclass*

所以它更好,推薦使用static_cast

我個人的偏好是基於這樣的代碼識字:

void* data = something;
MyClass* foo = reinterpret_cast<MyClass*>(data);
foo->bar();

要么

typedef void* hMyClass; //typedef as a handle or reference
hMyClass = something;
const MyClass& foo = static_cast<MyClass&>(*hMyClass);
foo.bar();

他們最終都做了同樣的事情,但static_cast似乎更適合中間件,應用程序環境,而重新解釋演員似乎更像你在較低級別的圖書館恕我直言中看到的東西。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM