C 语言中的 C 风格联合

联合类型以多种语言(如 C 语言)使用,以包含可以重叠的几种不同类型。换句话说,它们可能包含不同的字段,所有字段都以相同的内存偏移量开始,即使它们可能具有不同的长度和类型。这样既可以节省内存,又可以进行自动转换。以一个 IP 地址为例。在内部,IP 地址表示为整数,但有时我们想要访问不同的 Byte 组件,如 Byte1.Byte2.Byte3.Byte4。这适用于任何值类型,无论是 Int32 或 long 等原语,还是你自己定义的其他结构。

我们可以通过使用显式布局结构在 C#中实现相同的效果。

using System;
using System.Runtime.InteropServices;

// The struct needs to be annotated as "Explicit Layout"
[StructLayout(LayoutKind.Explicit)]
struct IpAddress
{
    // The "FieldOffset" means that this Integer starts, an offset in bytes.
    // sizeof(int) 4, sizeof(byte) = 1
    [FieldOffset(0)] public int Address;
    [FieldOffset(0)] public byte Byte1;
    [FieldOffset(1)] public byte Byte2;
    [FieldOffset(2)] public byte Byte3;
    [FieldOffset(3)] public byte Byte4;

    public IpAddress(int address) : this()
    {
        // When we init the Int, the Bytes will change too.
        Address = address;
    }

    // Now we can use the explicit layout to access the 
    // bytes separately, without doing any conversion.
    public override string ToString() => $"{Byte1}.{Byte2}.{Byte3}.{Byte4}";
}

以这种方式定义了 Struct,我们可以像在 C 中使用 Union 一样使用它。例如,让我们创建一个 IP 地址作为随机整数,然后通过更改它将地址中的第一个标记修改为'100’从’ABCD’到'100.BCD’:

var ip = new IpAddress(new Random().Next());
Console.WriteLine($"{ip} = {ip.Address}");
ip.Byte1 = 100;
Console.WriteLine($"{ip} = {ip.Address}");

输出:

75.49.5.32 = 537211211
100.49.5.32 = 537211236

查看演示