使用 Guid 的显式结构布局
Explicit struct layout with Guid
我正在尝试有一个明确的结构布局,我在其中将字节数组重新解释为 guid。这在 .net 4.7 和 .net 4.7.2 的 32 位 运行ning 时工作正常。但是当你 运行 它在 64 位时它在 .NET 4.7 中工作,但在 .NET 4.7.2 中似乎不起作用。此代码无效还是 .NET 中的错误?
[更新]:测试了更多配置。适用于 4.6.2 和 4.7,但不适用于 4.7.1 和 4.7.2。
[更新 2]:查看反汇编。在 64 位中,分配导致无操作。所以我认为很明显这是 .net 中的错误:
32位反汇编:
TestStruct t = new TestStruct();
03010480 lea edi,[ebp-58h]
03010483 xorps xmm0,xmm0
03010486 movq mmword ptr [edi],xmm0
0301048A movq mmword ptr [edi+8],xmm0
0301048F movq mmword ptr [edi+10h],xmm0
03010494 movq mmword ptr [edi+18h],xmm0
t.Guid1 = Guid.NewGuid();
03010499 lea eax,[ebp-58h]
0301049C mov dword ptr [ebp-64h],eax
0301049F lea ecx,[ebp-74h]
030104A2 call 723628F0
030104A7 mov edi,dword ptr [ebp-64h]
030104AA lea esi,[ebp-74h]
030104AD movq xmm0,mmword ptr [esi]
030104B1 movq mmword ptr [edi],xmm0
030104B5 movq xmm0,mmword ptr [esi+8]
030104BA movq mmword ptr [edi+8],xmm0
t.Guid2 = t.Guid1;
030104BF lea edi,[ebp-58h]
030104C2 add edi,10h
030104C5 lea esi,[ebp-58h]
030104C8 movq xmm0,mmword ptr [esi]
030104CC movq mmword ptr [edi],xmm0
030104D0 movq xmm0,mmword ptr [esi+8]
030104D5 movq mmword ptr [edi+8],xmm0
64 位反汇编:
TestStruct t = new TestStruct();
00007FFB054604B2 lea rcx,[rbp+78h]
00007FFB054604B6 vxorpd xmm0,xmm0,xmm0
00007FFB054604BB vmovdqu xmmword ptr [rcx],xmm0
00007FFB054604C0 vmovdqu xmmword ptr [rcx+10h],xmm0
t.Guid1 = Guid.NewGuid();
00007FFB054604C6 lea rcx,[rbp+78h]
00007FFB054604CA mov qword ptr [rbp+68h],rcx
00007FFB054604CE lea rcx,[rbp+58h]
00007FFB054604D2 call 00007FFB639BE8C0
00007FFB054604D7 mov rax,qword ptr [rbp+68h]
00007FFB054604DB vmovdqu xmm0,xmmword ptr [rbp+58h]
00007FFB054604E1 vmovdqu xmmword ptr [rax],xmm0
t.Guid2 = t.Guid1;
00007FFB054604E6 nop
重现代码:
[StructLayout(LayoutKind.Explicit, Size = SIZE)]
internal unsafe struct TestStruct
{
public const int SIZE = 32;
[FieldOffset(0)]
private fixed byte _data[SIZE];
[FieldOffset(0), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
public Guid Guid1;
[FieldOffset(16), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
public Guid Guid2;
}
internal class Program
{
private static void Main()
{
TestStruct t = new TestStruct();
t.Guid1 = Guid.NewGuid();
t.Guid2 = t.Guid1;
if (t.Guid1 != t.Guid2)
{
throw new InvalidOperationException("Guids aren't equal");
}
}
}
我认为问题可能与 FieldOffset 有关。 FieldOffset(16) 正在置换字节数组。
如果封装该字段并使用 属性 则应该没有问题。
[StructLayout(LayoutKind.Explicit, Size = SIZE)]
internal unsafe struct TestStruct
{
public const int SIZE = 32;
[FieldOffset(0)]
public fixed byte _data[SIZE];
[FieldOffset(0), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
private Guid guid1;
[FieldOffset(16), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
private Guid guid2;
public Guid Guid1 { get => guid1; set => guid1 = value; }
public Guid Guid2 { get => guid2; set => guid2 = value; }
}
事实证明这是 RyuJIT 中的一个错误并通过以下拉取请求解决。
我正在尝试有一个明确的结构布局,我在其中将字节数组重新解释为 guid。这在 .net 4.7 和 .net 4.7.2 的 32 位 运行ning 时工作正常。但是当你 运行 它在 64 位时它在 .NET 4.7 中工作,但在 .NET 4.7.2 中似乎不起作用。此代码无效还是 .NET 中的错误?
[更新]:测试了更多配置。适用于 4.6.2 和 4.7,但不适用于 4.7.1 和 4.7.2。
[更新 2]:查看反汇编。在 64 位中,分配导致无操作。所以我认为很明显这是 .net 中的错误:
32位反汇编:
TestStruct t = new TestStruct();
03010480 lea edi,[ebp-58h]
03010483 xorps xmm0,xmm0
03010486 movq mmword ptr [edi],xmm0
0301048A movq mmword ptr [edi+8],xmm0
0301048F movq mmword ptr [edi+10h],xmm0
03010494 movq mmword ptr [edi+18h],xmm0
t.Guid1 = Guid.NewGuid();
03010499 lea eax,[ebp-58h]
0301049C mov dword ptr [ebp-64h],eax
0301049F lea ecx,[ebp-74h]
030104A2 call 723628F0
030104A7 mov edi,dword ptr [ebp-64h]
030104AA lea esi,[ebp-74h]
030104AD movq xmm0,mmword ptr [esi]
030104B1 movq mmword ptr [edi],xmm0
030104B5 movq xmm0,mmword ptr [esi+8]
030104BA movq mmword ptr [edi+8],xmm0
t.Guid2 = t.Guid1;
030104BF lea edi,[ebp-58h]
030104C2 add edi,10h
030104C5 lea esi,[ebp-58h]
030104C8 movq xmm0,mmword ptr [esi]
030104CC movq mmword ptr [edi],xmm0
030104D0 movq xmm0,mmword ptr [esi+8]
030104D5 movq mmword ptr [edi+8],xmm0
64 位反汇编:
TestStruct t = new TestStruct();
00007FFB054604B2 lea rcx,[rbp+78h]
00007FFB054604B6 vxorpd xmm0,xmm0,xmm0
00007FFB054604BB vmovdqu xmmword ptr [rcx],xmm0
00007FFB054604C0 vmovdqu xmmword ptr [rcx+10h],xmm0
t.Guid1 = Guid.NewGuid();
00007FFB054604C6 lea rcx,[rbp+78h]
00007FFB054604CA mov qword ptr [rbp+68h],rcx
00007FFB054604CE lea rcx,[rbp+58h]
00007FFB054604D2 call 00007FFB639BE8C0
00007FFB054604D7 mov rax,qword ptr [rbp+68h]
00007FFB054604DB vmovdqu xmm0,xmmword ptr [rbp+58h]
00007FFB054604E1 vmovdqu xmmword ptr [rax],xmm0
t.Guid2 = t.Guid1;
00007FFB054604E6 nop
重现代码:
[StructLayout(LayoutKind.Explicit, Size = SIZE)]
internal unsafe struct TestStruct
{
public const int SIZE = 32;
[FieldOffset(0)]
private fixed byte _data[SIZE];
[FieldOffset(0), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
public Guid Guid1;
[FieldOffset(16), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
public Guid Guid2;
}
internal class Program
{
private static void Main()
{
TestStruct t = new TestStruct();
t.Guid1 = Guid.NewGuid();
t.Guid2 = t.Guid1;
if (t.Guid1 != t.Guid2)
{
throw new InvalidOperationException("Guids aren't equal");
}
}
}
我认为问题可能与 FieldOffset 有关。 FieldOffset(16) 正在置换字节数组。 如果封装该字段并使用 属性 则应该没有问题。
[StructLayout(LayoutKind.Explicit, Size = SIZE)]
internal unsafe struct TestStruct
{
public const int SIZE = 32;
[FieldOffset(0)]
public fixed byte _data[SIZE];
[FieldOffset(0), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
private Guid guid1;
[FieldOffset(16), MarshalAs(UnmanagedType.Struct, SizeConst = 16)]
private Guid guid2;
public Guid Guid1 { get => guid1; set => guid1 = value; }
public Guid Guid2 { get => guid2; set => guid2 = value; }
}
事实证明这是 RyuJIT 中的一个错误并通过以下拉取请求解决。