32位和64位系统下结构体的大小

6
.NET结构体设计准则中,它给出了结构体的最大合理大小为16字节。您如何确定您的结构体有多大,并且它是否受程序运行的体系结构的影响?这个值是仅适用于32位,还是两个架构都适用?
3个回答

7
这并不是一个硬性的值 - 它只是一个指导方针,一个经验法则。根据具体情况,24甚至32字节仍然可以完全合理 - 但如果你的结构体变得那么大,你应该真正地问问自己它是否适合作为一个结构体。它可能是适合的 - 在这种情况下,每次执行分配或将参数传递到方法(等等)时都要复制这32个字节的损失可能是正确的事情;在其他情况下,你应该真正使用一个类。
至于如何确定你的结构体有多大 - 通常很明显,因为通常值类型只包含其他值类型。如果你的结构体包含引用(或IntPtr/UIntPtr),那就更麻烦了 - 但这是相当罕见的。(正如Mehrdad所指出的,还有对齐填充的问题。)
再说一遍,我发现我想编写自己的结构体的情况非常罕见。你的情况是什么?

4
在.Net中,大部分类型在32位和64位程序之间的大小不会改变。框架定义的唯一两个会根据平台改变大小的值类型是:
- IntPtr - UIntPtr 除非你的结构体中直接或间接包含其中一个,否则它不应该在平台之间改变大小。
正如Mehrdad所指出的,另外两种根据平台改变大小的字段类别是:
- 指针 - 引用类型
但是所有这些类型都将以完全相同的方式进行更改。在32位平台上为4字节,在64位平台上为8字节。

3

是的,结构体的大小受到架构的影响。C#中的结构体在32位系统中按4字节边界对齐,在64位系统中按8字节对齐。

例如:

struct Foo
{
   int bar;
}

这个结构体在32位进程中占用4个字节,在64位进程中占用8个字节,即使“int bar”在32位和64位进程中都只占用4个字节。

更新:

我进行了一些测试。我编写了以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication3
{
    struct Bar
    {
        int a;
    }

    struct Foo
    {
        Uri uri;
        int a;
    }

    class Program
    {
        static void Main(string[] args)
        {
            Foo[] foo;
            long fooBefore = System.GC.GetTotalMemory(true);
            foo = new Foo[10];
            long fooAfter = System.GC.GetTotalMemory(true);

            Bar[] bar;
            long barBefore = System.GC.GetTotalMemory(true);
            bar = new Bar[10];
            long barAfter = System.GC.GetTotalMemory(true);

            Foo aFoo = new Foo();
            Bar aBar = new Bar();

            System.Console.Out.WriteLine(String.Format("[Foo] Size of array of 10: {0}, Marshal size of one: {1}", fooAfter - fooBefore, System.Runtime.InteropServices.Marshal.SizeOf(aFoo)));
            System.Console.Out.WriteLine(String.Format("[Bar] Size of array of 10: {0}, Marshal size of one: {1}", barAfter - barBefore, System.Runtime.InteropServices.Marshal.SizeOf(aBar)));
            System.Console.ReadKey();
        }
    }
}

作为一个64位进程,我得到了这个输出:
[Foo] Size of array of 10: 208, Marshal size of one: 16
[Bar] Size of array of 10: 88, Marshal size of one: 4

作为一个32位进程,我得到了这个输出:

[Foo] Size of array of 10: 92, Marshal size of one: 8
[Bar] Size of array of 10: 64, Marshal size of one: 4

观察结果:

  • 简单结构体Bar在32位和64位进程中似乎都占用4个字节
  • 另一个结构体Foo在32位进程中似乎占用8个字节(4个字节为int,4个字节为Uri的引用),但在64位进程中占用16个字节(4个字节为int,8个字节为Uri的引用,我认为还有4个字节用于对齐)

JaredPar似乎持不同意见 - 你知道这些信息可以在哪里获得吗? - thecoop
嗯,也许我在这里犯了错误。我会再仔细研究一下。 - waterlooalex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接