【问题标题】:Unions in C#: Structure Members Do Not Seem to be AlignedC# 中的联合:结构成员似乎没有对齐
【发布时间】:2012-12-11 01:27:51
【问题描述】:

我已经定义了以下结构来模拟 C++ 联合(最终将用于 C++ 互操作):

[StructLayout(LayoutKind.Sequential)]
internal struct STRUCT1
{
    public Guid guid;

    public String str1;
    public String str2;
}

[StructLayout(LayoutKind.Sequential)]
internal struct STRUCT2
{
    public Guid guid;

    public String str1;
    public String str2;

    public Int32 i1;
}

[StructLayout(LayoutKind.Explicit)]
internal struct MASTER_STRUCT_UNION
{
    [FieldOffset(0)]
    public STRUCT1 Struct1;

    [FieldOffset(0)]
    public STRUCT2 Struct2;
}

[StructLayout(LayoutKind.Sequential)]
internal struct MASTER_STRUCT
{
    public MASTER_STRUCT_UNION Union;
}

我编写了以下测试代码,它为Struct1.guid 赋值并测试Struct2.guid 是否相等:

class Class1
{
    public static void Test()
    {
        MASTER_STRUCT ms = new MASTER_STRUCT();

        bool match;
        ms.Union.Struct1.guid = new Guid(0xffeeddcc, 0xbbaa, 0x9988, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0);

        Console.WriteLine("Struct1.guid:\t\t{0}\n", ms.Union.Struct1.guid.ToString());

        Console.WriteLine("Struct2.integer:\t{0:x}", ms.Union.Struct2.i1);
        Console.WriteLine("Struct2.guid:\t\t{0}", ms.Union.Struct2.guid.ToString());


        match = ms.Union.Struct1.guid == ms.Union.Struct2.guid ? true : false;
    }
}  

为什么Struct2.guid 不等于Struct1.guidStruct2.guid 的一部分值似乎转移到Struct2.integer? IMO 的所有结构成员似乎都保持一致。

【问题讨论】:

    标签: c# struct unions


    【解决方案1】:

    LayoutKind.Sequential 仅影响此结构的非托管表示。这是因为结构包含非 blittable 类型(即字符串)。
    如果只有blittable types 存在,LayoutKind.Sequential 将控制托管和非托管表示 (reference)。

    在您的情况下,编译器决定将整数放在托管表示中的两个字符串之前(如果您在调试时将鼠标悬停在 ms 上并展开 STRUCT2,则可以看到这一点)。

    您可以通过在 STRUCT1STRUCT2 中使用 LayoutKind.Explicit 来解决此问题,因为 Explicit 会影响 blittable 和 non-blittable 类型的托管和非托管表示。

    【讨论】:

    • 这很好解释。谢谢你。现在我需要决定如果我将字符串声明更改为 IntPtr 声明并编组字符串值或利用您的建议使用 LayoutKind.Explicit,代码是否更易于维护。倾向于前者。
    • @LJVanKuiken 我也会去 IntPtrs。这样,代码就可以同时兼容 32 位和 64 位,而使用 Explicit,您需要对 FieldOffsets 使用条件编译,或者对 32 位和 64 位都使用 64 位填充(这可能会浪费内存)。
    猜你喜欢
    • 2015-09-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-30
    • 1970-01-01
    • 2014-01-18
    • 1970-01-01
    • 2012-08-07
    • 1970-01-01
    相关资源
    最近更新 更多