sizeof 运算符在 C# 中给出结构的额外大小 [重复]
Posted
技术标签:
【中文标题】sizeof 运算符在 C# 中给出结构的额外大小 [重复]【英文标题】:sizeof operator gives extra size of a struct in C# [duplicate] 【发布时间】:2016-06-27 21:13:14 【问题描述】:我正在尝试使用 sizeof 运算符检查所有变量(值类型)的大小。我浏览了其中一个msdn article,其中写着
对于所有其他类型,包括结构,sizeof 运算符只能用于不安全的代码块中
结构体不应包含任何引用类型的字段或属性
为此,我在我的项目属性中启用了不安全编译并创建了如下结构-
struct EmployeeStruct
int empId;
long salary;
并按如下方式使用它-
unsafe
size = sizeof(EmployeeStruct);
Console.WriteLine("Size of type in bytes is: 0", size);
在这里,我得到的输出是字节类型的大小为:16,但是通过查看结构,它应该是 12(4 表示 int,8 表示 long)。 有人可以在这里帮助我理解为什么我会得到 4 字节的额外大小吗?
【问题讨论】:
您提供的链接告诉您:“而 sizeof 返回由公共语言运行时分配的大小,包括任何填充” @EugenePodskal 它发生了很大变化——在 C# 上寻找问题答案的人不会看关于 C 的问题,它们是非常不同的语言,即使答案是相同的。 @GediminasMasaitis 然后他们会找到这个问题并阅读副本(嗯,至少他们应该)。但是,如果您认为值得付出努力,那么您可以编写一个适当的规范 C# 特定答案。在这种情况下,我还建议您将问题重命名为更易于搜索和直截了当的“sizeof 返回值大于预期”或类似的内容。 感谢 DavidG 的评论。你能告诉我更多为什么这个填充在获取任何内置类型(如 int、float 等)的大小时不会产生干扰,但是它为结构提供了额外的大小。 好建议 Eugene Podskal。我已更新标题以获得具体评论。 【参考方案1】:您不需要使用不安全的代码。推荐使用 System.Runtime.InteropServices.Marshal.SizeOf()
例如:Marshal.SizeOf(new EmployeeStruct());
返回 16 而不是 12,因为内存中的默认包大小是 8。
所以,对于:
struct EmployeeStruct
int empId; // 4 bytes
long salary; 8 bytes
//返回 16 而不是 12(因为最小单位是 8)
为:
struct EmployeeStruct
int empId; // 4 bytes
int empAge; // 4 bytes
long salary; 8 bytes
//也返回16
为了
struct EmployeeStruct
int empId; // 4 bytes
int empAge; // 4 bytes
int IdCompany; // 4 bytes
long salary; 8 bytes
返回 24 而不是 20(因为最小单位是 8)
我不知道你想要什么,但是如果你需要每个字段大小的总和,你可以试试这个函数:
public int SizeOf(Type t)
int s = 0;
var fields = t.GetFields(BindingFlags.Public | BindingFlags.Instance | BindingFlags.NonPublic);
foreach (var f in fields)
var x = f.FieldType;
s += x.IsPrimitive ? Marshal.SizeOf(x) : SizeOf(x);
return s;
对于您的情况,它返回 12 而不是 16,您可以将它用于复杂的结构,例如:
struct EmployeeStruct
int field1; // 4 bytes
long field2; // 8 bytes
Person p; // 12 bytes
struct Person
int field1; // 4 bytes
long field2; // 8 bytes
SizeOf(typeof(EmployeeStruct) 将返回 24 而不是 32,但请记住,REAL SIZE ON MEMORY 是 32,编译器使用 32 字节分配内存。
问候。
【讨论】:
但是为什么一个包含三个int
的结构的大小是12而不是16?
Thnx Gonzalo。但是 System.Runtime.InteropServices.Marshal.SizeOf 在编组后返回非托管分配的大小不是真的吗?难道我们没有办法获得正确的托管或 CLR 分配的大小吗?
我编辑了我的答案,也许我可以帮助你。问候。
@PrakashTripathi:正确。封送大小是 - 毫不奇怪 - 封送数据所需的缓冲区大小。 sizeof size 是结构消耗的内存量。这两件事没有理由必须相同,而且通常情况并非如此。
感谢 Eric Lippert。你采样来计算尺寸就像魅力一样。但是,这再次引发了一个小问题,即为什么在您的示例中 Marshal.SizeOf 不考虑填充?以上是关于sizeof 运算符在 C# 中给出结构的额外大小 [重复]的主要内容,如果未能解决你的问题,请参考以下文章