[英]How does casting uint8* to uint32* work?
這里有一個成員函數 :
uint8* CIwTexture::GetTexels() const;
例如,如果將返回值強制轉換為uint32*
,則強制轉換在這里如何工作? 如果返回值只是8位,那么如何將指向8位數據的指針轉換為32位?
指針僅僅是以地址作為其值的變量。 這意味着所有指針具有相同的大小(不要與“所有指針的數據具有相同的大小”混淆,這是不正確的)。
編譯器處理指針所指向的數據所需的所有信息都是從其類型推斷出來的。 這意味着uint32_t
指向的uint32_t
將被視為32位數據,而uint8_t
數據將被視為8位數據。
所有這些信息僅在編譯時保存,並且編譯器根據其處理的指針生成機器代碼。 這意味着從一個指針到另一個的強制轉換僅與編譯器相關 ,因此它知道在生成代碼時如何處理數據。 在運行時,沒有任何變化,沒有值被復制或移動。
大致來說,您的內存布局可能如下所示:
括號部分(數據的大小)是對編譯器的提示,因此可以按程序員的意圖對待數據。
當您轉換為uint32_t
,您的內存布局將大致如下所示:
現在,您可以從中推斷出以下幾點:
最后,考慮以32位訪問此數據的含義:
例如,如果將其轉換為uin32 *,該轉換如何工作? 我的意思是,如果返回的只是8位,則如何將指向8位數據的指針轉換為32位?
它返回一個內存地址,而不是該內存地址存儲的8位。 該地址指向內存中的某個位置。 當您將其分配給uint32*
它仍指向相同的內存位置。
現在,當取消引用該指針時,它將從指針指向的地址的4個連續的內存位置中讀取值(將其與取消引用uint8
且僅讀取一個的情況進行比較)。
// somewhere in the memory
uint32 x;
uint8_t* foo()
{
// Now imagine here x being constructed from
// individual bytes or somehow
// ...
// return pointer to the first byte of x as `uint8_t`
return (uint8_t*)&x;
}
現在,這里的問題就在調用方上-函數簽名中沒有任何內容告訴調用方他需要/可以將其視為uint32_t
。 在這種情況下,必須對此進行明確記錄。
返回值是指向uint8的指針。 C ++中的指針可以轉換為任何其他類型的指針。 當取消引用該指針時,“魔術”就會開始-取消引用返回的值就是指針的類型。 例如,如果您這樣做:
uint32* ptr = (uint32*)functionThatReturnsPtrToUint8();
uint32 value = *ptr;
然后,“值”變量將僅使用ptr指向的前4個字節,並將其轉換為uint32值(具體實現方式取決於底層系統的字節序)。
返回的不是8位。 返回是一個指針(一個內存地址)。 指針的類型告訴編譯器如何看待內存。 在這種情況下,它表示應一次將存儲器處理一個字節。 如果將指針uint32*
為uint32*
,則告訴編譯器將數據分成四個字節。 但是,該函數出於某種原因返回了指向字節的指針。 數據可能不打算以四個字節的塊進行處理。 如果將指針轉換為其他類型,則表示正在告訴編譯器以可能不希望的方式使用數據。
指針只是地址,強制類型轉換不會改變地址(指針的值),但會提示編譯器。
但是,當您將指針轉換為其他類型時,會遇到對齊問題,並且編譯器會抱怨。 根本問題是對於某些體系結構,必須以適當的對齊方式訪問內存,例如,不能取消引用奇數地址,否則CPU可能會發生故障/陷阱。
如果您知道自己在做什么,可以安全地忽略它(在這種情況下,我假設返回的指針正確對齊)。
最后,要投射指針,您只需執行以下操作:
uint32_t* p = (uint32_t*) mem;
要么
uint32_t* p = static_cast<uint32_t*>( mem );
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.