Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/291.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/macos/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在c中访问结构数组中的元素成员#_C# - Fatal编程技术网

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

C# 如何在c中访问结构数组中的元素成员#,c#,C#,假设我们有一个结构数组条目[2],它在内存中的布局如下:[hashcode(4字节)、next(4字节)、hashcode(4字节)、next(4字节)] [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 1)] struct Entry { [FieldOffset(0)] public int hashCode; [FieldOffset(4)] pu

假设我们有一个结构数组条目[2],它在内存中的布局如下:[hashcode(4字节)、next(4字节)、hashcode(4字节)、next(4字节)]

    [StructLayout(LayoutKind.Explicit, Size = 8, Pack = 1)]
    struct Entry
    {
        [FieldOffset(0)]
        public int hashCode;
        [FieldOffset(4)]
        public int next;
    }
现在我要访问这个条目[0]。接下来是代码中的

class Test
    {
        Entry[] entries = new Entry[2];

        void AccessElement()
        {
            int n = entries[0].next; 
        }
    }
因此,在AccessElement方法中,我只有一行代码,即:条目[0]。接下来,我想知道CLR如何帮助我们访问此元素。
我现在有两个想法,我将给你伪代码。
1)。想法1
int n=(&entries+0)->下一步

获取entries对象的地址,获取第一个元素(偏移量0),然后访问下一个成员的值(相对于元素基址的4字节)

想法2

Entry entry = Copy(&entries[0],8);
int n = entry.next;
将entries对象的第一个元素(偏移量0)复制到当前堆栈中,并返回当前堆栈对象的下一个成员

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

多谢各位


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

                   Entry[] entries = new Entry[2];
        00007FFB4B6D47F0 mov         rcx,7FFB4B96361Ah
        00007FFB4B6D47FA mov         edx,2
        00007FFB4B6D47FF call        00007FFBAA902630
        00007FFB4B6D4804 mov         qword ptr[rbp + 20h], rax
        00007FFB4B6D4808 mov         rax,qword ptr[rbp + 20h]
        00007FFB4B6D480C mov         qword ptr[rbp + 30h], rax
                    int n = entries[1].next;
        00007FFB4B6D4810 mov         rax,qword ptr[rbp + 30h]
        00007FFB4B6D4814 mov         edx,1
        00007FFB4B6D4819 cmp         rdx,qword ptr[rax + 8]
        00007FFB4B6D481D jb          00007FFB4B6D4824
        00007FFB4B6D481F call        00007FFBAADA2660
        00007FFB4B6D4824 lea         rax,[rax+rdx*8+10h]  
        00007FFB4B6D4829 mov         eax,dword ptr[rax + 4]  
        00007FFB4B6D482C mov         dword ptr[rbp + 2Ch], eax
也许我想得太多了?我只是看了一下IL代码:
当条目类型为reference时,这是IL

        // Entry1[] entries = new Entry1[2];
        IL_0001 ldc.i4.2
        IL_0002 newarr      ConsoleApp9.Entry1
        IL_0007 stloc.0
        // int n = entries[1].next;
        IL_0008 ldloc.0
        IL_0009 ldc.i4.1
        IL_000A ldelem.ref
        IL_000B ldfld       System.Int32 ConsoleApp9.Entry1::next
        IL_0010 stloc.1
如果条目类型为结构,则这是IL

    // Entry[] entries = new Entry[2];
    IL_0001 ldc.i4.2
    IL_0002 newarr    ConsoleApp9.Entry
    IL_0007 stloc.0
    // int n = entries[1].next;
    IL_0008 ldloc.0
    IL_0009 ldc.i4.1
    IL_000A ldelema   ConsoleApp9.Entry
    IL_000F ldfld System.Int32 ConsoleApp9.Entry::next
    IL_0014 stloc.1
对于结构化数组,指令是ldelema:将指定数组索引处数组元素的地址作为类型&(托管指针)加载到计算堆栈的顶部

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


那么真相就出来了?

你可以自己研究一下:编译代码并查看生成的IL(例如使用ildasm)。@KlausGütter确实应该自己看看。只是不在IL。他们需要查看零售构建中的JIT代码,以了解他们的要求。IL不必匹配程序集级指令,因为几乎所有优化都是通过JIT进行的,而不是在编译过程中进行的。在访问数组时,肯定不会将数组元素复制到任何局部变量。不需要这样做,因为数组是下面的连续内存块,因此其元素可以通过指令级的偏移量进行访问,而复制会根据数组的大小及其元素的大小造成严重的性能影响。根据反汇编代码:1)
lea-rax[rax+rdx*8+10h]
-加载索引为
1
的数组元素地址(1加载到
rdx
下部的
edx
rax
包含数组实例地址,10h是x64系统上CLR实例头的长度)到
rax
寄存器,2)
mov-eax,dword-ptr[rax+4]
-将索引为
1
(由
rax
寻址)的元素的
next
字段的值移动到
eax
寄存器和3)
mov-dword-ptr[rbp+2Ch],eax
将该值存储在堆栈上某个寻址的局部变量中。正如您所看到的,不会复制整个数组元素。