[英]void pointer type cast with (unsigned int *) and (unsigned int **)
unsigned int num = 101;
void * p = #
void ** pp = &p;
unsigned int *get_data_1 = NULL;
unsigned int *get_data_2 = NULL;
get_data_1 = *((unsigned int *)pp);
get_data_2 = *((unsigned int **)pp);
這里get_data_1和get_data_2會有什么區別呢?
我使用 (unsigned int *) 和 (unsigned int **) 進行類型轉換。
這兩個操作都會調用Undefined Behavior 。 pp
指向的類型void*
的值分別通過不兼容類型unsigned int
或unsigned int*
的左值表達式訪問。 這違反了嚴格的別名規則。
由於這兩個操作都是UB ,因此這兩個操作之間沒有明確的區別。
正確的訪問應該是首先取消引用pp
以獲得void*
類型的值並使用從void*
到unsigned int*
的隱式轉換。 最后取消引用正確類型的指針:
unsigned int *get_data_3 = *pp;
return *get_data_3;
TL;博士
不要這樣做,出於多種原因,這是危險且不正確的 C 語言。 我對初學者的一般建議是永遠不要使用 cast 運算符 - 不應該有很多情況下您實際上需要使用它。
通常,只要不存在與指向的類型有關的對齊問題,C 允許在不兼容的對象指針之間進行狂野和危險的指針轉換。 (6.3.2.3/7)
但是,如果您首先轉換為不兼容的類型,然后取消引用指針,則可能會出現各種未定義的行為。6.7.6.1:
對於要兼容的兩種指針類型,兩者都應具有相同的限定,並且都應是指向兼容類型的指針。
還有關於“左值訪問”(6.5)的整個“嚴格別名”問題。
具體來說:
(unsigned int *)pp
指針轉換可能沒問題,因為pp
指向對齊的地址。*((unsigned int *)pp)
調用未定義的行為,因為void*
類型的左值作為unsigned int
訪問,並且它們不是兼容的類型。unsigned int *get_data_1 = <unsigned int lvalue>
是違反約束的 - 無效 C。根據 6.5.16.1。 C 從未允許將整數分配給指針,反之亦然,需要顯式轉換。(unsigned int **)pp
同樣,指針轉換本身“可能還可以”。 但同樣unsigned int**
與void**
不兼容。 值得注意的是,關於void*
轉換的特殊通用規則不適用於void**
。*((unsigned int **)pp)
將void*
作為unsigned int*
訪問。 這又是一個嚴格的別名違規,因為盡管我們可以將 void* 轉換為/從void*
轉換為任何對象指針,但它們不需要具有相同的內部表示(盡管在實踐中很有可能)。 根據引用的 6.7.6.1,它們不是兼容的類型。unsigned int *get_data_2 = <unsigned int* lvalue>
沒問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.