如何在 C# 中访问结构体数组中的元素成员

Zen*_*eng 7 c#

假设我们有一个结构体数组Entry[2],它在内存中的布局如下所示:[hashcode(4byte),next(4byte),hashcode(4byte),next(4byte)]

\n\n
    [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 1)]\n    struct Entry\n    {\n        [FieldOffset(0)]\n        public int hashCode;\n        [FieldOffset(4)]\n        public int next;\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以现在我将在我的代码中访问此Entry[0].next

\n\n
class Test\n    {\n        Entry[] entries = new Entry[2];\n\n        void AccessElement()\n        {\n            int n = entries[0].next; \n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

所以在AccessElement方法中,我只有一行代码,即:entries[0].next,我想知道CLR如何帮助我们访问这个元素。
\n我现在有两个想法,我将给你伪代码。
\n 1).idea 1
\n int n = (&entries+0)->next
\n 获取entries对象的地址,获取第一个元素(偏移量0),并访问下一个成员的值(相对于元素基地址的4字节)。

\n\n

2).想法2

\n\n
Entry entry = Copy(&entries[0],8);\nint n = entry.next;\n
Run Code Online (Sandbox Code Playgroud)\n\n

将条目对象的第一个元素(偏移量 0)复制到当前堆栈中,并返回当前堆栈对象条目的下一个成员

\n\n

这两个想法是我对CLR访问结构体数组中元素成员的想法,这和我在某些情况下是否使用struct有关,毕竟大量数据mov有一些开销。所以有人可以告诉我吗CLR 如何访问结构体数组中元素成员的真实模式?调试和发布之间有什么区别吗?

\n\n

谢谢

\n\n
\n\n

这是一个接收器代码。有人可以帮我读一下吗

\n\n
                   Entry[] entries = new Entry[2];\n        00007FFB4B6D47F0 mov         rcx,7FFB4B96361Ah\n        00007FFB4B6D47FA mov         edx,2\n        00007FFB4B6D47FF call        00007FFBAA902630\n        00007FFB4B6D4804 mov         qword ptr[rbp + 20h], rax\n        00007FFB4B6D4808 mov         rax,qword ptr[rbp + 20h]\n        00007FFB4B6D480C mov         qword ptr[rbp + 30h], rax\n                    int n = entries[1].next;\n        00007FFB4B6D4810 mov         rax,qword ptr[rbp + 30h]\n        00007FFB4B6D4814 mov         edx,1\n        00007FFB4B6D4819 cmp         rdx,qword ptr[rax + 8]\n        00007FFB4B6D481D jb          00007FFB4B6D4824\n        00007FFB4B6D481F call        00007FFBAADA2660\n        00007FFB4B6D4824 lea         rax,[rax+rdx*8+10h]  \n        00007FFB4B6D4829 mov         eax,dword ptr[rax + 4]  \n        00007FFB4B6D482C mov         dword ptr[rbp + 2Ch], eax\n
Run Code Online (Sandbox Code Playgroud)\n\n

也许我想太多了?我只是看了一下IL代码:
\n这是当Entry是引用类型时的IL

\n\n
        // Entry1[] entries = new Entry1[2];\n        IL_0001 ldc.i4.2\n        IL_0002 newarr      ConsoleApp9.Entry1\n        IL_0007 stloc.0\n        // int n = entries[1].next;\n        IL_0008 ldloc.0\n        IL_0009 ldc.i4.1\n        IL_000A ldelem.ref\n        IL_000B ldfld       System.Int32 ConsoleApp9.Entry1::next\n        IL_0010 stloc.1\n
Run Code Online (Sandbox Code Playgroud)\n\n

如果 Entry 是结构类型,则这是 IL

\n\n
    // Entry[] entries = new Entry[2];\n    IL_0001 ldc.i4.2\n    IL_0002 newarr    ConsoleApp9.Entry\n    IL_0007 stloc.0\n    // int n = entries[1].next;\n    IL_0008 ldloc.0\n    IL_0009 ldc.i4.1\n    IL_000A ldelema   ConsoleApp9.Entry\n    IL_000F ldfld System.Int32 ConsoleApp9.Entry::next\n    IL_0014 stloc.1\n
Run Code Online (Sandbox Code Playgroud)\n\n

对于结构化数组,指令为 ldelema \xef\xbc\x9a 将指定数组索引处的数组元素的地址作为 &(托管指针)类型加载到计算堆栈的顶部。

\n\n

对于引用数组,指令为 ldelem.ref \xef\xbc\x9a 将指定数组索引处包含对象引用的元素作为 O 类型(对象引用)加载到计算堆栈的顶部。

\n\n

那么真相大白了吗?

\n