首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >在C#中布尔值的大小是多少?它真的需要4个字节吗?

在C#中布尔值的大小是多少?它真的需要4个字节吗?
EN

Stack Overflow用户
提问于 2015-02-14 17:52:08
回答 1查看 31.5K关注 0票数 143

我有两个带有字节数组和布尔值的结构:

代码语言:javascript
复制
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct struct1
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public byte[] values;
}

[StructLayout(LayoutKind.Sequential, Pack = 4)]
struct struct2
{
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
    public bool[] values;
}

和以下代码:

代码语言:javascript
复制
class main
{
    public static void Main()
    {
        Console.WriteLine("sizeof array of bytes: "+Marshal.SizeOf(typeof(struct1)));
        Console.WriteLine("sizeof array of bools: " + Marshal.SizeOf(typeof(struct2)));
        Console.ReadKey();
    }
}

这给出了以下输出:

代码语言:javascript
复制
sizeof array of bytes: 3
sizeof array of bools: 12

似乎一个boolean需要4个字节的存储空间。理想情况下,boolean只需要一个比特(falsetrue01等)。

这是怎么回事?boolean类型真的这么低效吗?

EN

回答 1

Stack Overflow用户

发布于 2015-02-14 19:53:00

bool类型有一个曲折的历史,在语言运行时之间有许多不兼容的选择。这始于Dennis Ritchie的一个历史性的设计选择,他发明了C语言。它没有bool类型,可选的是int,其中值0表示false,任何其他值都被认为是true。

这一选择在Winapi中得到了延续,这是使用pinvoke的主要原因,它有一个BOOL的类型定义函数,它是C编译器的int关键字的别名。如果您不应用显式的MarshalAs属性,那么C#布尔值将被转换为BOOL值,从而生成一个4字节长的字段。

无论您做什么,您的struct声明都需要与您所使用的语言中的运行时选择相匹配。如上所述,BOOL用于winapi,但大多数C++实现选择字节,大多数COM自动化互操作使用VARIANT_BOOL,它是一个缩写。

C# bool的实际大小是一个字节。CLR的一个强大的设计目标是你找不到答案。布局是一个在很大程度上依赖处理器的实现细节。处理器对变量类型和对齐非常挑剔,错误的选择会严重影响性能并导致运行时错误。通过使布局不可发现,.NET可以提供不依赖于实际运行时实现的通用类型系统。

换句话说,你总是需要在运行时编组一个结构来确定布局。此时进行从内部布局到互操作布局的转换。如果布局相同,这可能会非常快;当字段需要重新排列时,速度会很慢,因为这总是需要创建结构的副本。这方面的技术术语是blittable,将blittable结构传递给本机代码是很快的,因为pinvoke编组程序可以简单地传递一个指针。

性能也是bool不是单比特的核心原因。很少有处理器可以让位直接寻址,最小的单位是一个字节。需要额外的指令来从字节中提取位,这不是免费的。而且它从来不是原子的。

使用sizeof(bool),C#编译器不会害羞地告诉您它需要1个字节。这仍然不能很好地预测一个字段在运行时需要多少字节,CLR还需要实现.NET内存模型,并且它承诺简单的变量更新是原子的。这要求变量在内存中正确对齐,以便处理器可以在单个内存总线周期内对其进行更新。通常情况下,bool实际上需要4或8个字节的内存。为确保下一个成员正确对齐而添加的额外填充。

CLR实际上利用了布局不可发现的优势,它可以优化类的布局并重新排列字段,从而使填充最小化。比方说,如果你有一个包含bool + int + bool成员的类,那么它将占用1+ (3) +4+1+ (3)字节的内存,(3)是填充,总共12字节。50%的浪费。自动布局重新排列为1+1+ (2) +4=8字节。只有类具有自动布局,默认情况下结构具有顺序布局。

更糟糕的是,在使用支持AVX指令集的现代C++编译器编译的C++程序中,bool可能需要多达32个字节。这施加了32字节的对齐要求,所以布尔变量可能以31字节的填充结束。这也是为什么.NET抖动不会发出单指令多数据指令的核心原因,除非显式包装,否则它不能获得对齐保证。

票数 260
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28514373

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档