2009-07-21 62 views
9

我有一個關於LayoutKind.Explicit屬性集的結構的小問題。正如你所看到的,我聲明瞭struct,其中帶有64位的fieldTotal,最後32字節是fieldFirst,前32字節是fieldSecond。在將fieldfirstfieldSecond設置爲Int32.MaxValue之後,我希望fieldTotalInt64.MaxValue,這實際上不會發生。爲什麼是這樣?我知道C#並不真的支持C++聯合,也許它只會在調用時讀取值,但是當我們嘗試自己設置值時,它不會很好地處理它。如何在C#中模擬C++聯合?

[StructLayout(LayoutKind.Explicit)] 
struct STRUCT { 
    [FieldOffset(0)] 
    public Int64 fieldTotal; 

    [FieldOffset(0)] 
    public Int32 fieldFirst; 

    [FieldOffset(32)] 
    public Int32 fieldSecond; 
} 

     STRUCT str = new STRUCT(); 
     str.fieldFirst = Int32.MaxValue; 
     str.fieldSecond = Int32.MaxValue; 
     Console.WriteLine(str.fieldTotal); // <----- I'd expect both these values 
     Console.WriteLine(Int64.MaxValue); // <----- to be the same. 
     Console.ReadKey(); 

回答

10

原因是FieldOffsetAttribute需要多個字節作爲參數 - 而不是位數。這按預期工作:

[StructLayout(LayoutKind.Explicit)] 
struct STRUCT 
{ 
    [FieldOffset(0)] 
    public Int64 fieldTotal; 

    [FieldOffset(0)] 
    public Int32 fieldFirst; 

    [FieldOffset(4)] 
    public Int32 fieldSecond; 
} 
+0

再加上Reed&Jared對簽名和未簽名的說法。 – 2009-07-21 23:37:18

6

查看十六進制值,如果Int32.MaxValue和Int64.MaxValue應提供答案。

關鍵是最重要的一點。對於一個正整數,最高有效位僅設置爲負數。所以Int32的最大值是0,然後是整個系列的1。順序不重要,只是至少會有一個0位。 Int64.MaxValue也是如此。

現在考慮工會應該如何工作。它將基本上將值的位排列在一起。所以現在你有一組64位的長度,它包含兩個0位值。每個Int32.MaxValue實例一個。這不能等於Int64.MaxValue,因爲它只能包含一個0位。

奇怪的是,如果將fieldSecond設置爲Int32.MinValue,您可能會得到您正在查找的行爲。

編輯錯過了,您還需要將其設置爲FieldOffset(4)。

4

Ben M提供的更重要的因素之一 - 你的定義是不正確設置。

這就是說,這不會工作 - 即使在C + +與聯盟。您指定的值不會(也不應該)爲相同的值,因爲您使用的是已簽名(而非未簽名)的整數。使用帶符號的int(Int32),您將有一個0位,後跟1位。當你完成這個聯合時,你最終會得到一個0比特,然後是一堆1比特,然後是另一個0比特,然後是一堆1比特......第二個0比特是你搞砸了。

如果您使用了UInt32/UInt64,這將工作屬性,因爲額外的符號位不存在。

+0

是的,你是對的。用你說的話和本說,它按預期工作。謝謝! – 2009-07-21 23:40:53