I'm investigating on IPC data exchange with non-.Net applications based on Memory Mapped Files. Therefore I'm trying to understand on how C# can organize physical data layouts for that. 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
Bool_00 -> Type: Boolean, ArrayLength: 0, Offset: 0, Size: 4
Bool_01 -> Type: Boolean, ArrayLength: 1, Offset: 4, Size: 4
Bool_02 -> Type: Boolean, ArrayLength: 0, Offset: 8, Size: 4
Bool_03 -> Type: Boolean, ArrayLength: 2, Offset: 12, Size: 4
Bool_05 -> Type: Boolean, ArrayLength: 3, Offset: 16, Size: 4
Bool_08 -> Type: Boolean, ArrayLength: 4, Offset: 20, Size: 4
Bool_12 -> Type: Boolean, ArrayLength: 5, Offset: 24, Size: 5
Bool_17 -> Type: Boolean, ArrayLength: 7, Offset: 30, Size: 7
Bool_24 -> Type: Boolean, ArrayLength: 8, Offset: 38, Size: 8
Bool_32 -> Type: Boolean, ArrayLength: 9, Offset: 46, Size: 9
Bool_41 -> Type: Boolean, ArrayLength: 2, Offset: 56, Size: 4
Bool_43 -> Type: Boolean, ArrayLength: 0, Offset: 60, Size: 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??
Does anybody know, why?