2014-01-18 63 views
0

如何安全地讀取一個void作爲int指向char?如何安全地讀取指向char的void *作爲int?

示例:測試系統中字符的第一位,其中8位字符訪問速度比32位字節慢得多。

char c = 'B'; // a char here to illustrate the potentially dangerous case, but the 
       // point is this could be a char, could be an int... I am just 
       // interested in the first bit 
void *v = &c; 
int i = *(int *)v; 
if (i & 0x01) 
{ 
    printf("yep"); 
} 

似乎工作,但如果我的字符(C)是正確的,在分配給此進程的有效記憶的邊緣,這將是讀入無效的內存?還是系統足夠聰明,可以在前8位之後停止複製?

感謝

+0

讀取8位字符將至少與讀取32位int相同。*寫作*可能不會,但這是一個不同的問題。 – Roddy

+0

1.在C++或C之間選擇2.猜測它是C,因爲調用了printf。 3.避免void指針。你正在進入空白/黑洞 –

+0

4.不要使用C風格的演員(如果這是C++) – olevegard

回答

1

該系統是不是足夠聰明,你的程序很容易出現內存訪問違規

3

它在所有情況下,不確定的行爲。

在大多數實際系統中,如果c靠近內存頁的末尾並且相鄰頁被標記爲不可讀,則它將正常從c和相鄰內存中讀取,失敗(具有訪問衝突(又名分段錯誤))。

在較小但仍然不重要的系統數量中,您可能會遇到對齊錯誤和/或讀取與c重疊的32位值,但在起始位置以外的某個位置可能會讀取到c

但是,如果編譯器發現你這樣做了,它有權從標準中以非常破碎的方式「優化」你所有的代碼。


如果你害怕的,其中8位訪問慢的系統,然後使用int_fast8_t代替char。這可以讓你的構建環境選擇更好的變量大小。

+0

它是如何定義的? 'char * - > void * - > int * - > int'未定義? – Brandon

+0

@CantChooseUsernames:你正在讀取一個'int&'類型的值,它引用的內存不存在'int'。 (int存在於有足夠存儲空間的地方,而'c'對於int類型的對象來說存儲空間不足,參見標準3.8p1)您還沒有安全地派生指針,也沒有保證正確的對齊。 –

+0

從5.2.9.13開始:類型爲「指向cv1'void的指針」可以被轉換爲類型爲「指向cv2」T「的指針的前值,」其中'T'爲 對象類型...如果原始指針值代表 存儲器中一個字節的地址'A',並且'A'滿足'T'的對齊要求,則所產生的指針 值表示與原始指針值相同的地址,即'A'。 **其他 指針轉換的結果未指定。** –

1

這只是未定義的行爲。

另一方面,我可以想象一下,這將工作的情況。請注意,在聲明c後,您聲明v。由於c處於堆棧狀態,通過將其地址轉換爲void*,然後取消引用它,您可能會得到int,它將由c的1個字節和v的3個字節組成。但這只是衆多可能實現中的一種。

2

不,這是不安全的。

而你的用例是完全人爲的,因爲我有從來沒有聽說過讀取32位值的系統比讀取8位的系統快。如果有的話,它有時是相反的。

(即使你找到了這樣的系統,離開「優化」像這樣的編譯器。它會做一個更好的工作。)

+1

某些系統根本無法本地讀取8位值。訪問'int8_t'變量是通過使用32位讀取和位掩碼和移位完成的。 (但是在這樣的系統中,掩模和移位幾乎總是非常快,甚至是免費的) –

+0

@BenVoigt你的意思是需要幾個指令?而不是通常的32/64位存儲器訪問和處理器自動屏蔽所需的字節? – Roddy

+1

有時候內存總線會遮蔽,有時內存讀取是全寬的,處理器會這樣做,我相信在極少情況下需要額外的指令。 –

1

int變量將被裝載3個字節加你想要加載的一個。此外,你投到int可能會導致錯位。而且,根據你在if中掩蓋的方式,這個演員陣容在平臺不同的平臺之間是不可移植的。這是一種糟糕的做法,請重新構建您的系統以避免當前的情況。

相關問題