[英]Safely cast void* to int
如果將應用程序編譯為產生x32圖像,則取決於體系結構的整數類型可能是16位寬,32s位寬或大於2個字節的任何值。 void*
大小將為4(在x32上始終為4 ???)。 這意味着將int
傳遞給void*
是可以的,但是如果發現在給定的體系結構上, void*
比int
寬(標准僅保證int
至少為2個字節)。
C標准n1124§6.3.2.3指針
5整數可以轉換為任何指針類型。 除非先前指定,否則結果是實現定義的,可能未正確對齊,可能未指向引用類型的實體,並且可能是陷阱表示形式。56)
6任何指針類型都可以轉換為整數類型。 除非先前指定,否則結果是實現定義的。 如果結果不能用整數類型表示,則行為是不確定的。 結果不必在任何整數類型的值范圍內。
在以下代碼段中將void*
強制轉換為int
可能會產生不確定的行為。
typedef enum tagENUM
{
WSO_1,
WSO_2,
//...
WSO_COUNT
} ENUM;
/* I cannot change handler signature because this is callback. I have to cast void*
* to ENUM however inside */
void handler( int i, int j, void *user_data)
{
ENUM mOperation;
mOperation = (ENUM)reinterpret_cast<int>(user_data);
}
// somewhere
handler( 1, 2, (void*)WSO_1); // UB? We can imagine that someone passes to handler
// (void*)WSO_131072 which don't fit into 16 bits
// So is there a place opened for UB?
如果這是正確的,那就打開了可能發生鼻粘膜重症的問題-我該如何安全地寫出這個問題呢? 我可以使用intptr_t
來確保結果適合嗎?
void handler( int i, int j, void *user_data)
{
ENUM mOperation;
uintptr_t p_mOperation = reinterpret_cast<uintptr_t>( user_data);
if ( p_mOperation > WSO_COUNT ) {
send_error(conn, 500, http_500_error, "Error: %s", strerror(ERRNO));
return;
}
mOperation = static_cast<ENUM_WS_OPERATION>( p_mOperation); // now safe?
是的,它可能導致不確定的行為。 如果改用intptr_t
,則沒有未定義的行為。
但是,通常您可以重寫代碼,以使指針指向預期的整數,而不是強制轉換為整數。
在第二個示例中,您有一個雜燴。 您想使用intptr_t
或void *
指向int
。 不是intptr_t *
或uintptr_t *
。
我的首選解決方案是user_data
始終指向數據; 指向的數據類型由調用的處理程序或其他參數確定。
這一點:
mOperation = (ENUM)reinterpret_cast<int>(user_data);
提示您已經無法控制自己在做什么。 您正在執行兩次強制轉換,這始終表明發生了不良情況(好像reinterpret_cast尚未表明這一點)。
從這還不清楚您要做什么。 當然(void *)對於傳遞不是數據的值是不適當的強制轉換。 它用於傳遞指向任意數據緩沖區的指針,在那里人們希望另一端的東西可以從數據中得出所需的信息。
所以這:
handler( 1, 2, (void*)WSO_1);
完全是錯誤的。
但是,鑒於WSO_1
實際上是一個enum
,而且我不知道void *
實際上小於枚舉的任何平台,您應該可以這樣做
mOperation = reinterpret_cast<ENUM>(user_data);
當客戶將枚舉類型轉換為空*時,該客戶已經進入了可疑區域,並且該轉換不會使情況變得更糟。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.