簡體   English   中英

為什么結構的sizeof是不安全的

[英]Why sizeof of a struct is unsafe

MSDN明確指出

對於所有其他類型(包括結構),sizeof運算符只能用於不安全的代碼塊。

C#語言規范更加精確:

  1. 未指定成員打包到結構中的順序。
  2. 出於對齊目的,在結構的開頭,結構內和結構的末尾可能存在未命名的填充。
  3. 用作填充的位的內容是不確定的。
  4. 當應用於具有結構類型的操作數時,結果是該類型的變量中的總字節數,包括任何填充。

但是CLR如何處理以下結構:

[StructLayout(LayoutKind.Explicit, Size = 1, Pack = 1)]
public struct MyStruct
{
    [FieldOffset(0)] public byte aByte;
}

public struct MyEmptyStruct { }

MyStruct我們明確地強制執行布局,大小以及如何通過StructLayout屬性打包它。 該結構應該在內存中具有1個字節的大小。

另一方面, MyEmptyStruct是空的,我們可以假設內存中的大小將是0字節 - 即使這樣的結構很可能不會被使用它仍然是一個有趣的案例。

當嘗試使用sizeof(MyStruct)sizeof(MyEmptyStruct)計算這些結構的大小時,編譯器會拋出以下錯誤:

' * '沒有預定義的大小,因此sizeof只能在不安全的上下文中使用

我想知道為什么在這種情況下使用sizeof被認為是unsafe 問題不是要求解決方法,也不是要求計算結構大小的正確方法,而是要關注原因。

我想知道為什么在這種情況下使用sizeof被認為是不安全的。

馬修沃特森的評論擊中了頭部。 您將如何使用安全代碼處理該信息? 它對任何東西都沒用(*)。 它不會告訴您需要為編組分配多少非托管字節; 那是Marshal.SizeOf 它僅對指針算法很有用,那為什么它應該在安全子集中​​呢?


(*)可以公平地說,對於一個安全的sizeof ,有一些奇怪的角落用例可以采用包含托管類型的結構。 假設您有一個泛型集合類,它將分配一堆數組,並希望確保這些數組不會移動到大對象堆中; 如果您可以獲取包含托管對象的結構的大小,那么您可以非常輕松地編寫此代碼,並且它不需要任何指針算法。 但事實仍然是sizeof是專門為指針算法而設計的,而不是為了讓你可以對數組的垃圾收集啟發式做最后的運行。

問題中有很多錯誤的假設,我將逐一解決它們:

在MyStruct中,我們明確地強制執行布局

你沒有。 [StructLayout]屬性僅在編組結構值時才真正有效。 Marshal.StructureToPtr(),也被pinvoke marshaller使用。 只有這樣才能保證封送值具有所請求的布局。 CLR保留在其認為合適時布置結構的權利。 它將對齊結構成員,以便使用結構的代碼盡可能快,如果需要插入空字節。 如果這樣的填充字節留下足夠的空間,那么它甚至會交換成員以獲得更小的布局。 除了使用調試器查看訪問結構成員的機器代碼之外,這完全是不可發現的。 一些 [StructLayout]屬性影響布局,LayoutKind.Explicit確實支持聲明聯合。 映射算法的確切細節未記錄,可能會發生變化,並且很大程度上取決於目標機器架構。

結果是該類型變量中的總字節數,包括任何填充。

事實並非如此,實際結構可能比聲明的結構小。 可以通過將成員交換到填充中。

該結構應該在內存中具有1個字節的大小。

這種情況很少發生。 局部變量也在內存中對齊,在32位處理器上為4個字節,在64位處理器中為8個字節。 除非結構存儲在數組中,否則實際上它將在堆棧上或堆上的對象內部占用4或8個字節。 由於成員對齊很重要,因此這種對齊很重要。

MyEmptyStruct為空,我們可以假設內存中的大小為0字節

即使結構為空,變量也始終至少有1個字節。 這避免了諸如具有占空零字節的非空數組之類的含糊之處。 也是其他語言的規則,比如C ++。

為什么在這種情況下使用sizeof被認為是不安全的

需要明確的是,在原始值類型上使用sizeof並不需要從.NET 2開始就不安全 。但是對於結構體,有可能使用sizeof()直接尋址內存,例如將其添加到IntPtr中。 使用sizeof()是錯誤的選擇並且應該是Marshal.SizeOf()的風險相當大。 我猜想在結構上使用sizeof()的實用性是如此之低,因為結構應該總是很小,並且以錯誤的方式攻擊IntPtrs的幾率非常高,以至於它們使它不安全

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM