C# 中的 C++ 联合

问题描述 投票:0回答:8

我正在将用 C++ 编写的库翻译为 C#,并且关键字“union”存在一次。在一个结构中。

将其翻译成 C# 的正确方法是什么?它有什么作用?它看起来像这样;

struct Foo {
    float bar;

    union {
        int killroy;
        float fubar;
    } as;
}
c# c++ unions
8个回答
101
投票

您可以为此使用显式字段布局:

[StructLayout(LayoutKind.Explicit)] 
public struct SampleUnion
{
    [FieldOffset(0)] public float bar;
    [FieldOffset(4)] public int killroy;
    [FieldOffset(4)] public float fubar;
}

未经测试。 这个想法是两个变量在结构中具有相同的位置。 您当然可以只使用其中之一。

有关联合的更多信息,请参见 struct 教程


25
投票

如果不了解它的使用方式,您就无法真正决定如何处理它。如果它只是为了节省空间,那么你可以忽略它,只使用一个结构体。

然而,这通常不是使用联合的原因。使用它们有两个常见原因。一是提供两种或多种访问相同数据的方式。例如,int 和 4 字节数组的并集是分离 32 位整数字节的(多种)方法之一。

另一种情况是结构体中的数据来自外部源,例如网络数据包。通常,包含联合的结构体的一个元素是一个 ID,它告诉您联合的哪种风格正在生效。

在这两种情况下,您都不能盲目地忽略联合并将其转换为两个(或更多)字段不重合的结构。


6
投票

在 C/C++ 中,联合用于在同一内存位置覆盖不同的成员,因此,如果您有一个 int 和 float 的联合,它们都使用相同的 4 字节内存来存储,显然写入一个会破坏另一个(因为 int 和 float 有不同的位布局)。

在 .Net 中,微软选择了更安全的选择,并且没有包含此功能。

编辑:互操作除外


4
投票

如果您使用

union
将一种类型的字节映射到另一种类型,那么在 C# 中您可以使用
BitConverter
来代替。

float fubar = 125f; 
int killroy = BitConverter.ToInt32(BitConverter.GetBytes(fubar), 0);

或者;

int killroy = 125;
float fubar = BitConverter.ToSingle(BitConverter.GetBytes(killroy), 0);

0
投票

您可以编写一个简单的包装器,但在大多数情况下只使用一个对象就不会那么混乱。

    public class MyUnion
    {
        private object _id;
        public T GetValue<T>() => (T)_id;
        public void SetValue<T>(T value) => _id = value;
    }

0
投票
[System.Runtime.InteropServices.StructLayout(LayoutKind.Explicit)]
struct TestUnion
{
    [System.Runtime.InteropServices.FieldOffset(0)]
    public int i;

    [System.Runtime.InteropServices.FieldOffset(0)]
    public double d;

    [System.Runtime.InteropServices.FieldOffset(0)]
    public char c;

    [System.Runtime.InteropServices.FieldOffset(0)]
    public byte b;
}

-1
投票

就我个人而言,我会忽略 UNION 并将 Killroy 和 Fubar 作为单独的字段实现

public struct Foo
{
    float bar;
    int Kilroy;
    float Fubar;
}

使用 UNION 可以保存由 int 分配的 32 位内存......现在不会决定应用程序的成败。


-5
投票
public class Foo
{
    public float bar;
    public int killroy;

    public float fubar
    {
        get{ return (float)killroy;}
        set{ killroy = (int)value;}
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.