简体   繁体   English

C#.NET对布尔字段和固定数组的StructLayout感到困惑

[英]C# .NET Confused about StructLayout of bool fields and fixed arrays

I'm investigating on IPC data exchange with non-.Net applications based on Memory Mapped Files. 我正在研究与基于内存映射文件的非.Net应用程序进行IPC数据交换。 Therefore I'm trying to understand on how C# can organize physical data layouts for that. 因此,我试图了解C#如何为此组织物理数据布局。 So I started with unsafe structs as from what I read before this seemed to be the right technology. 所以我从不安全的结构开始,因为在我认为这是正确的技术之前,我已经阅读了不安全的结构。 When playing with different data layouts for bool type values I got confused about this code and the results: 当为布尔类型值使用不同的数据布局时,我对此代码和结果感到困惑:

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

namespace UnsafeBoolArrayStruct
{
    [StructLayout(LayoutKind.Sequential, Pack = 2)]
    public unsafe struct StructOfBool
    {
        public bool Bool_00;
        public fixed bool Bool_01[1];
        public bool Bool_02;
        public fixed bool Bool_03[2];
        public fixed bool Bool_05[3];
        public fixed bool Bool_08[4];
        public fixed bool Bool_12[5];
        public fixed bool Bool_17[7];
        public fixed bool Bool_24[8];
        public fixed bool Bool_32[9];
        public fixed bool Bool_41[2];
        public bool Bool_43;
    }

    class Program
    {
        static void Main(string[] args)
        {
            StructOfBool dummy = new StructOfBool();

            int _Size = Marshal.SizeOf(typeof(StructOfBool));
            int _Pack = typeof(StructOfBool).StructLayoutAttribute.Pack;
            Console.WriteLine("{0} -> Pack: {1}, Size: {2}", typeof(StructOfBool).Name, _Pack, _Size);
            foreach (FieldInfo fi in typeof(StructOfBool).GetFields())
            {
                Type _Type;
                int _ArrayLength = 0;
                _Size = Marshal.SizeOf(fi.FieldType);
                var _Offset = Marshal.OffsetOf(typeof(StructOfBool), fi.Name);

                // Check for arrays
                var _Attribute = fi.GetCustomAttributes(typeof(FixedBufferAttribute), false);
                if (_Attribute.Length > 0)
                {   // Array
                    _Type = ((FixedBufferAttribute)_Attribute[0]).ElementType;
                    _ArrayLength = ((FixedBufferAttribute)_Attribute[0]).Length;
                }
                else
                    // Singular field
                    _Type = fi.FieldType;

                // Process found data
                Console.WriteLine("{0} -> Type: {1}, ArrayLength: {2}, Offset: {3}, Size: {4}", fi.Name, Type.GetTypeCode(_Type), _ArrayLength, _Offset, _Size);
            }
            Console.ReadKey();
        }
    }
}

The result shows like this: 结果显示如下:

StructOfBool -> Pack: 2, Size: 64 StructOfBool->包:2,大小:64

Bool_00 -> Type: Boolean, ArrayLength: 0, Offset: 0, Size: 4 Bool_00->类型:布尔值,ArrayLength:0,偏移量:0,大小:4

Bool_01 -> Type: Boolean, ArrayLength: 1, Offset: 4, Size: 4 Bool_01->类型:布尔值,数组长度:1,偏移量:4,大小:4

Bool_02 -> Type: Boolean, ArrayLength: 0, Offset: 8, Size: 4 Bool_02->类型:布尔值,ArrayLength:0,偏移量:8,大小:4

Bool_03 -> Type: Boolean, ArrayLength: 2, Offset: 12, Size: 4 Bool_03->类型:布尔值,ArrayLength:2,偏移量:12,大小:4

Bool_05 -> Type: Boolean, ArrayLength: 3, Offset: 16, Size: 4 Bool_05->类型:布尔值,数组长度:3,偏移量:16,大小:4

Bool_08 -> Type: Boolean, ArrayLength: 4, Offset: 20, Size: 4 Bool_08->类型:布尔值,数组长度:4,偏移量:20,大小:4

Bool_12 -> Type: Boolean, ArrayLength: 5, Offset: 24, Size: 5 Bool_12->类型:布尔值,ArrayLength:5,偏移量:24,大小:5

Bool_17 -> Type: Boolean, ArrayLength: 7, Offset: 30, Size: 7 Bool_17->类型:布尔值,数组长度:7,偏移量:30,大小:7

Bool_24 -> Type: Boolean, ArrayLength: 8, Offset: 38, Size: 8 Bool_24->类型:布尔值,数组长度:8,偏移量:38,大小:8

Bool_32 -> Type: Boolean, ArrayLength: 9, Offset: 46, Size: 9 Bool_32->类型:布尔值,ArrayLength:9,偏移量:46,大小:9

Bool_41 -> Type: Boolean, ArrayLength: 2, Offset: 56, Size: 4 Bool_41->类型:布尔值,数组长度:2,偏移量:56,大小:4

Bool_43 -> Type: Boolean, ArrayLength: 0, Offset: 60, Size: 4 Bool_43->类型:布尔值,数组长度:0,偏移量:60,大小:4

It looks like that packing is handled differently at least on singular fields compared to arrays. 看起来与数组相比,至少在奇异字段上对打包的处理不同。 Why does Bool00 with one bool value take 4 bytes, Bool03 with two bool values also take 4 bytes, but Bool12 with five values just 5 bytes?? 为什么带有一个布尔值的Bool00占用4个字节,为什么带有两个布尔值的Bool03也占用4个字节,但是带有五个值的Bool12却只有5个字节?

Does anybody know, why? 有人知道,为什么吗?

but Bool12 with five values just 5 bytes?? 但是带有五个值的Bool12只有5个字节?

To be fair, what your result shows is that Bool12 actually takes six bytes in the struct. 公平地说,您的结果表明Bool12实际上在结构中占用了六个字节。

The Marshal.SizeOf() method doesn't tell you anything about the managed representation of the data, including the size of fields in a struct. Marshal.SizeOf()方法不会告诉您有关数据的托管表示的任何信息,包括结构中字段的大小。 That method is needed for code that needs to know what the unmanaged version of a given type will need in terms of space. 对于需要知道给定类型的非托管版本在空间方面需要什么的代码,需要使用该方法。

I don't know all the layout rules for managed types off the top of my head. 我不了解所有托管类型的布局规则。 But your observations can be explained by considering that the actual size of an array need not be a multiple of the minimum size of the element of the array, or even of the array itself. 但是,您的观察可以通过考虑数组的实际大小而不是数组元素甚至数组本身的最小大小的倍数来解释。 So you get bool and bool[] fields that are four bytes, because they can't be any smaller, but once you get beyond that size, the pack (alignment) value takes over, putting the fields at even-valued offsets. 因此,您会得到四个字节的boolbool[]字段,因为它们不能再小,但是一旦超过该大小,pack(对齐)值就会接管,使这些字段处于偶数偏移量。

The reported length of these fields you are obtaining by using Marshal.SizeOf() which, as I noted above, isn't related to the managed storage at all. 您通过使用Marshal.SizeOf()获得的这些字段的报告长度 ,如上所述,它与托管存储完全无关。 It's telling you how many bytes a destination buffer in unmanaged code would need to be to store the information in that field. 它告诉您非托管代码中的目标缓冲区需要多少字节才能将信息存储在该字段中。

Even if it were related (and by coincidence, in a way it is…just because the CLR side works very similarly to the unmanaged side), that doesn't change the fact that fields in your struct need to be aligned to two-byte boundaries, so the offsets for subsequent fields don't always match up with the reported length of their respective preceding field. 即使它是相关的(巧合的是,只是因为CLR端与非托管端的工作方式非常相似),这也不会改变以下事实:结构中的字段需要对齐为两个字节边界,因此后续字段的偏移量并不总是与其相应的先前字段的报告长度相匹配。


Related links: 相关链接:
How to check the number of bytes consumed by my structure? 如何检查我的结构消耗的字节数?
sizeof vs Marshal.SizeOf sizeof vs元帅。
Computing the Size of a Structure 计算结构的大小
What's the difference? 有什么不同? sizeof and Marshal.SizeOf sizeof和Marshal.SizeOf

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM