2013-05-17 41 views
0

我將一個數據緩衝區轉換爲較大尺寸的結構指針。它會導致任何問題?我在Visual Studio上試過下面的代碼,沒有發現警告或錯誤。鑄造較大尺寸結構的緩衝區

#include <iostream> 
using namespace std; 

struct test 
{ 
    char var1; 
    char var2; 
    long var3; 
}; 
void function(char* data); 

int main (void) 
{ 
    char data[5] = {1, 0, 0, 3, 4}; 
    function(data); 

    system("Pause"); 
    return 0; 
} 

void function(char* data) 
{ 
    test* pTest = reinterpret_cast<test*>(data); // casting 
    printf("%x\n", pTest->var1); 
    printf("%x\n", pTest->var2); 
    printf("%x\n", pTest->var3); 
} 
+2

我會說這是一個問題,你是*做這個*首先。數據的字節大小爲5,但根據編譯器的填充行爲,「struct test」的字節大小至少爲6,可能爲8。因此,當您訪問'var3'時,重新解釋的數據會在數據末尾讀取到某個未知的內存區域。這應該會在運行時導致分段錯誤(但可能不會,這取決於'malloc()'在您的系統上的工作方式)。 TL; DR;如果這恰好適合你,那只是運氣。爲了使它變成明智的代碼,'sizeof(data)'必須> ='sizeof(test)'。 – kampu

+1

任何你看着這只是一個壞主意。 – WhozCraig

+0

這看起來可能會起作用,甚至可能會像您期望的那樣運行,但它有可能在隨機時間導致不正確的數據和崩潰。這不會有好處。 – Steve

回答

0

這類鑄件是非常危險的(換句話說,你說的編譯 - 「我知道,我這樣做」),所以在這種情況下,你必須檢查是否正確等鑄件youself。

4

你必須明白,內存管理是如何工作的。你靜態地分配了數組data,所以它將被放在棧中(它保存帶有被調用函數局部變量的幀)。堆棧是爲每個進程靜態分配的(也就是說,通過進程生命週期它具有不變的大小)。

因爲現在,堆棧看起來更少這樣的:

data[1, 0, 0, 3, 4] 

現在你調用的函數function。新框架被放在堆棧上,所以看起來更少這樣的:

data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b] 
(main data)   (function data) 

現在,你施放數據到你的類型,其尺寸至少爲6個字節(讓我們假設,可能需要8或更多的字節,取決於類的內容對齊)。所以,你試圖訪問這些字節:

data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b] 
(main data)   (function data) 
    * * * * *     * 

(請注意,我的棧的可視化被簡化,這是可能的,有調用函數後留下的更多的數據)。

您在以後的printf中訪問的所有內存都屬於您的應用程序,因此操作系統不會引發訪問衝突錯誤。你閱讀數據,所以你不會損害任何東西。但現在假設,你會寫點東西給pTest->var3。這些字節將被改寫:

data[1, 0, 0, 3, 4] | return-pointer[a b c d] pTest [e f a b] 
(main data)   (function data) 
    * * # # #     # 

現在看,你只是破壞了返回指針 - 它主要是有可能的,雖然試圖退出function並返回main你的程序會崩潰現在。

通常它是強烈建議只投出兼容的數據類型(大小相等)。編譯器通常無法知道,如果你的演員陣容有效(特別是,如果你在路上投了指針void *)。所以你應該非常在意在你的節目中製作劇集。

0

reinterpret_cast<xxx>(yyy)告訴編譯器「相信我,我知道我在這裏做什麼」。這意味着你必須絕對確定你自己所做的是正確的。

在這種特殊情況下,您導致了未定義的行爲,因爲您的結構大於您傳入的數據,這絕對不是一件好事 - 它可能會導致幾乎任何事情發生(並且包括「something類似於你所期望的「) - 更糟的是,它可能會因編譯時使用的選項而異,因此它可能看起來在調試模式下工作,然後在發佈模式下編譯時會出現問題。至少var3將有一些未定義的內容,基於以下事實:至少部分(而不是全部)var3超出了您定義的數據。這取決於long的尺寸和對齊方式。在Windows中,這是4個字節並對齊到四個字節。因此,在兩個字符字段和long數據之間有2個字節的空間。

但是,如果您知道自己在做什麼,並且在function代碼中不訪問var3,則可以使用此類方案。

最後,如果這是一個通訊科協議的一部分,它可能需要在來看待從「什麼是填充/需要添加」的觀點。如果協議需要一定的間隔,則需要正確處理 - 例如,同時,處理器可能對「長」讀取的對齊有嚴格的要求。因此,如果數據實際上以BYTE|BYTE|LONG打包在一起,則可能說服編譯器以這種方式打包數據結構,只是讓處理器在訪問「雙字節對齊」long值時崩潰。

換句話說:在數據之上的數據結構的鑄造,是不是預期可能導致的問題,所有的方式長度,而不需要編譯器說什麼。