none
怎么计算struct结构中每个成员的位置 RRS feed

  • 问题

  • 比说我定义了一个struct
        public struct _Apple
        {
            public int amount;
            public short color;
            public float volume;
            public byte[] name;//已知大小是11
        }
    那这样,设amout的起始位置为0,那int占2个字节,所以color的起始位置是2;short占几个字节,再得到volume的起始位置。
    这样,如果我的struct成员超级多,我怎么可以根据struct的定义,自动得到每一个成员的起始位置是第几个字节呢?
    人工算是可以,但是好麻烦啊。

    2009年7月27日 2:33

答案

  • 你好!
         可以使用System.Runtime.InteropServices.StructLayoutAttribute特性来告诉CLR,我们希望字段如何布局!
         指定为LayoutKind.Sequential,代表让CLR保留我们设定的字段顺序!
         指定为LayoutKine.Auto,代表让CLR自己排列字段的顺序!

         如果我们没有指定这个特性,编译器会选择他认为最好的方式!
         对C#编译器来说,引用类型选择的是LayoutKind.Auto,而值类型选择的是LayoutKind.Sequential
    周雪峰
    2009年7月28日 0:42
    版主
  • 默认情况下结构的成员没有固定的地址顺序。成员的起始地址随时可能变化。

    Please mark the post answered your question as the answer, and click the chartreuse pyramid floating over "Vote as helpful" to mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights.
    Visual C++ MVP
    2009年7月27日 14:25
    版主
  • 实际上你可以自己指定字段的物理位置的:
    [StructLayout(LayoutKind.Explicit)]
    public struct SYSTEM_INFO
    {
    [FieldOffset(0)] public ulong OemId;
    [FieldOffset(8)] public ulong PageSize;
    [FieldOffset(16)] public ulong ActiveProcessorMask;
    [FieldOffset(24)] public ulong NumberOfProcessors;
    [FieldOffset(32)] public ulong ProcessorType;
    }
    

    周雪峰
    2009年7月28日 4:54
    版主
  • 你好,

    这个是.NET的内部实现,一个自定义类型的成员在内存中的位置和顺序不是你定义的顺序,所以我们是不能直接计算这个位置的,可以使用周雪峰的方法或你可以使用Debugger去查看位置。

    Runtime为了让内存的使用更有效率(这也和数据对齐有关),他会重新排列,这个问题你可以看下〈〈Essential .NET〉〉第三章的 type fundamentals,那里有详细的解释。同时参考下这篇文章,关于对象的生成:
    http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

    希望这有帮助,有问题告诉我们来继续讨论。

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    2009年7月29日 2:39
    版主

全部回复

  • 一般还是需要自己写,不太好处理,比如 string 类型具体占多长是你在具体业务是确定的,并不是固定长度。
    知识改变命运,奋斗成就人生!
    2009年7月27日 4:04
    版主
  • 用typeof(_Apple)  得到type 就可以枚举成员了   当然string一直是个问题
    答案900, 目标五颗星 Aurvana Air, 音乐真的是随风飘来的 凉宫春日 永无止境的八月 你到底什么时候结束阿。。。。
    2009年7月27日 4:35
    版主
  • 默认情况下结构的成员没有固定的地址顺序。成员的起始地址随时可能变化。

    Please mark the post answered your question as the answer, and click the chartreuse pyramid floating over "Vote as helpful" to mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights.
    Visual C++ MVP
    2009年7月27日 14:25
    版主
  • 你好!
         可以使用System.Runtime.InteropServices.StructLayoutAttribute特性来告诉CLR,我们希望字段如何布局!
         指定为LayoutKind.Sequential,代表让CLR保留我们设定的字段顺序!
         指定为LayoutKine.Auto,代表让CLR自己排列字段的顺序!

         如果我们没有指定这个特性,编译器会选择他认为最好的方式!
         对C#编译器来说,引用类型选择的是LayoutKind.Auto,而值类型选择的是LayoutKind.Sequential
    周雪峰
    2009年7月28日 0:42
    版主
  • 你好!
         可以使用System.Runtime.InteropServices.StructLayoutAttribute特性来告诉CLR,我们希望字段如何布局!
         指定为LayoutKind.Sequential,代表让CLR保留我们设定的字段顺序!
         指定为LayoutKine.Auto,代表让CLR自己排列字段的顺序!

         如果我们没有指定这个特性,编译器会选择他认为最好的方式!
         对C#编译器来说,引用类型选择的是LayoutKind.Auto,而值类型选择的是LayoutKind.Sequential
    周雪峰

    赫赫,补充一下,还需要设置 StructLayoutAttribute.Pack, 避免编译器帮你对齐。

    应该没有自动计算的方法吧,而且即使用人工算也不麻烦啊,就算有 100 个字段,还不是十来分钟的事情。如果字段数量超过 100 个, 呃, 建议你改改设计吧。

    最后,int 的长度是 4, short 的长度是 2....
    2009年7月28日 1:44
  • 默认情况下结构的成员没有固定的地址顺序。成员的起始地址随时可能变化。

    Please mark the post answered your question as the answer, and click the chartreuse pyramid floating over "Vote as helpful" to mark other helpful posts as helpful. This posting is provided "AS IS" with no warranties, and confers no rights.
    Visual C++ MVP

    谢谢斑竹的回复。
    我并不要起始地址,我指的是成员的相对地址。我现在只能傻乎乎的根据成员类型来一个个的计算……
    不能从内存(我不懂瞎说的)这种很高深的方法来实现么?
    2009年7月28日 1:58
  • 你好!
         可以使用System.Runtime.InteropServices.StructLayoutAttribute特性来告诉CLR,我们希望字段如何布局!
         指定为LayoutKind.Sequential,代表让CLR保留我们设定的字段顺序!
         指定为LayoutKine.Auto,代表让CLR自己排列字段的顺序!

         如果我们没有指定这个特性,编译器会选择他认为最好的方式!
         对C#编译器来说,引用类型选择的是LayoutKind.Auto,而值类型选择的是LayoutKind.Sequential
    周雪峰

    ……谢谢版主……可惜偶编程知识比较浅薄,没能看懂。。
    看来偶还是老老实实的口算吧。
    2009年7月28日 2:23
  • 实际上你可以自己指定字段的物理位置的:
    [StructLayout(LayoutKind.Explicit)]
    public struct SYSTEM_INFO
    {
    [FieldOffset(0)] public ulong OemId;
    [FieldOffset(8)] public ulong PageSize;
    [FieldOffset(16)] public ulong ActiveProcessorMask;
    [FieldOffset(24)] public ulong NumberOfProcessors;
    [FieldOffset(32)] public ulong ProcessorType;
    }
    

    周雪峰
    2009年7月28日 4:54
    版主
  • 你好,

    这个是.NET的内部实现,一个自定义类型的成员在内存中的位置和顺序不是你定义的顺序,所以我们是不能直接计算这个位置的,可以使用周雪峰的方法或你可以使用Debugger去查看位置。

    Runtime为了让内存的使用更有效率(这也和数据对齐有关),他会重新排列,这个问题你可以看下〈〈Essential .NET〉〉第三章的 type fundamentals,那里有详细的解释。同时参考下这篇文章,关于对象的生成:
    http://msdn.microsoft.com/en-us/magazine/cc163791.aspx

    希望这有帮助,有问题告诉我们来继续讨论。

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    2009年7月29日 2:39
    版主
  • 实际上你可以自己指定字段的物理位置的:
    [StructLayout(LayoutKind.Explicit)]
    
    public struct SYSTEM_INFO
    
    {
    
    [FieldOffset(0)] public ulong OemId;
    
    [FieldOffset(8)] public ulong PageSize;
    
    [FieldOffset(16)] public ulong ActiveProcessorMask;
    
    [FieldOffset(24)] public ulong NumberOfProcessors;
    
    [FieldOffset(32)] public ulong ProcessorType;
    
    }
    
    
    
    

    周雪峰
    谢谢。
    以前在C的时候,取地址再相减,就很容易的获得结构成员的偏离地址。
    不知道C#怎么倒没有兼容这种功能呢。。
    2009年7月29日 3:22
  • C#是基于.NET Framework的语言,生成托管的代码,由Runtime管理内存,所以这和C/C++是不同的,看下下面的文字,我从Essential .NET书中引用的:

    By default, the exact memory layout of a type is opaque. The CLR uses a virtualized layout scheme and will often reorder the fields to optimize memory access and usage, as in Figure 3.1. Note that the order of declaration was isGoodCustomer, lastName, balance, and extra, followed by firstInitial. If the CLR laid out the type's fields in order of declaration, it would have to insert a good deal of padding between fields in order to avoid unaligned access to individual fields something that would kill performance. To avoid this, the CLR reorders the fields so that no packing is necessary. On the author's 32-bit IA-32 machine, that means that the following order is used: balance, lastName, firstInitial, and isGoodCustomer, followed by extra. This layout results in no wasted padding as well as perfectly aligned data. Be aware, however, that the exact layout policy used by the CLR is undocumented, and one should not rely on a specific policy for all versions of the CLR.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    2009年7月30日 9:30
    版主