什么是一个布尔值,在C#中的大小?它是否真的需要4个字节? [英] What is the size of a boolean In C#? Does it really take 4-bytes?

查看:208
本文介绍了什么是一个布尔值,在C#中的大小?它是否真的需要4个字节?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have two structs with arrays of bytes and booleans:

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;
}

和下面的代码:

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();
    }
}

这给了我下面的输出:

sizeof array of bytes: 3
sizeof array of bools: 12

这似乎是一个布尔需要4个字节的存储空间。理想情况下,布尔将只需要一个位(真正 0 1 等)。

It seems to be that a boolean takes 4 bytes of storage. Ideally a boolean would only take one bit (false or true, 0 or 1, etc..).

这是怎么回事吗?是布尔键入真的如此低效?

What is happening here? Is the boolean type really so inefficient?

推荐答案

布尔的类型都有语言运行时之间不兼容的众多选择一个曲折的历史。这开始与丹尼斯里奇,发明了C语言的家伙做一个历史的设计选择。它没有一个的布尔的类型,选择是的 INT 的,其中,0值表示的的任何其它的值被认为的

The bool type has a checkered history with many incompatible choices between language runtimes. This started with an historical design-choice made by Dennis Ritchie, the guy that invented the C language. It did not have a bool type, the alternative was int where a value of 0 represents false and any other value was considered true.

这个选择是在WINAPI,主要理由使用PInvoke的发扬光大,它有 BOOL 这是C编译器的 INT 的关键字的别名。如果你不申请一个明确的[的MarshalAs]属性,那么一个C#的布尔的转换为BOOL,从而产生一个字段是4字节长。

This choice was carried forward in the Winapi, the primary reason to use pinvoke, it has a typedef for BOOL which is an alias for the C compiler's int keyword. If you don't apply an explicit [MarshalAs] attribute then a C# bool is converted to a BOOL, thus producing a field that is 4 bytes long.

不管你做什么,你的结构声明需要与运行中的选择与你互操作语言的一对。如前所述,BOOL为WINAPI但大多数C ++实现选择的字节的,大多数COM自动化互操作使用VARIANT_BOOL这是一个的

Whatever you do, your struct declaration needs to be a match with the runtime choice made in the language you interop with. As noted, BOOL for the winapi but most C++ implementations chose byte, most COM Automation interop uses VARIANT_BOOL which is a short.

实际的的C#布尔的大小是一个字节。 CLR的一个强大的设计目标是,你无法找到答案。布局是一个实现细节取决于处理器太多。处理器是有关变量类型和对齐很挑剔,错误的选择可能显著影响性能并导致运行时错误。通过使布局不可发现,.NET可以提供不依赖于实际运行时实现一个通用类型系统。

The actual size of a C# bool is one byte. A strong design-goal of the CLR is that you cannot find out. Layout is an implementation detail that depends on the processor too much. Processors are very picky about variable types and alignment, wrong choices can significantly affect performance and cause runtime errors. By making the layout undiscoverable, .NET can provide a universal type system that does not depend on the actual runtime implementation.

在换句话说,你总是有一个元帅结构在运行时确定下来的布局。此时转换过程中的内部的布局到互操作布局而成。如果布局是相同的,缓慢的领域时,需要重新安排,因为这总是需要创建结构的副本可以非常快。这种情况的技术术语是的 blittable 的,路过一个blittable结构为本地代码是快,因为PInvoke的编组可以简单地传递一个指针。

In other words, you always have to marshal a structure at runtime to nail down the layout. At which time the conversion from the internal layout to the interop layout is made. That can be very fast if the layout is identical, slow when fields need to be re-arranged since that always requires creating a copy of the struct. The technical term for this is blittable, passing a blittable struct to native code is fast because the pinvoke marshaller can simply pass a pointer.

性能也是最核心的原因,为什么一个的布尔的不是一个单一的位。很少有处理器,使一个位可直接寻址的,最小的单位是字节。一个的额外的的指令要求的鱼出位字节,但这并不是免费的。而这是从来没有的原子。

Performance is also the core reason why a bool is not a single bit. There are few processors that make a bit directly addressable, the smallest unit is a byte. An extra instruction is required to fish the bit out of the byte, that doesn't come for free. And it is never atomic.

C#编译器是不是要告诉你,它需要1个字节,使用的sizeof(布尔),否则害羞。这仍然不是一个领域的多少字节需要在运行时一个梦幻般的预测,CLR还需要实现.NET的内存模型,它承诺,简单的变量更新的原子的。需要变量在内存中正确对齐,以便该处理器可以与单个存储器总线周期更新。漂亮的时候,一个的布尔的实际上需要4个或8个字节的内存因为这个原因。补充说,微胖,以确保的下次的成员正确对齐。

The C# compiler isn't otherwise shy about telling you that it takes 1 byte, use sizeof(bool). This is still not a fantastic predictor for how many bytes a field takes at runtime, the CLR also needs to implement the .NET memory model and it promises that simple variable updates are atomic. That requires variables to be properly aligned in memory so the processor can update it with a single memory-bus cycle. Pretty often, a bool actually requires 4 or 8 bytes in memory because of this. Extra padding that was added to ensure that the next member is aligned properly.

在CLR实际利用布局是无法发现的,它可以优化一类和布局,以便填充最小化重新安排的字段。所以说,如果你有一类与布尔+ INT +布尔成员,那么将采取1 + 3 + 4 + 1 +(3)字节的内存,(3)填充,共计12字节。 50%的浪费。自动布局重新排列,以1 + 1 +(2)+ 4 = 8个字节。只有一类具有自动布局,结构都默认顺序布局。

The CLR actually takes advantage of layout being undiscoverable, it can optimize the layout of a class and re-arrange the fields so the padding is minimized. So, say, if you have a class with a bool + int + bool member then it would take 1 + (3) + 4 + 1 + (3) bytes of memory, (3) is the padding, for a total of 12 bytes. 50% waste. Automatic layout rearranges to 1 + 1 + (2) + 4 = 8 bytes. Only a class has automatic layout, structs have sequential layout by default.

更多bleakly,一个的布尔的可能需要在多达32个字节C ++程序与支持AVX指令集现代C ++编译器编译。其中规定了32字节对​​齐要求,布尔变量可以用31个字节的填充结束。另外,核心原因为什么.NET抖动未发出SIMD指令,除非明确地包裹着,它不能得到保证对齐

More bleakly, a bool can require as many as 32 bytes in a C++ program compiled with a modern C++ compiler that supports the AVX instruction set. Which imposes a 32-byte alignment requirement, the bool variable may end up with 31 bytes of padding. Also the core reason why a .NET jitter does not emit SIMD instructions, unless explicitly wrapped, it can't get the alignment guarantee.

这篇关于什么是一个布尔值,在C#中的大小?它是否真的需要4个字节?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆