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