2009-07-21 65 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