Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the size and alignment of C# fixed bool array in struct?

Tags:

c#

pinvoke

When doing P/Invoke, it is important to make the data layout match.

We can control the layout of struct by using some attribute.

For example:

struct MyStruct 
{
    public bool f;
}

gives a size of 4. While we can tell compiler to make it a 1 byte bool to match C++ type of bool:

struct MyStruct
{
    [MarshalAs(UnmanagedType.I1)]
    public bool f;
}

gives a size of 1.

These make sense. But when I test fixed bool array, I was confused.

unsafe struct MyStruct
{
    public fixed bool fs[1];
}

gives a size of 4 bytes. and

unsafe struct MyStruct
{
    public fixed bool fs[4];
}

still gives a size of 4 bytes. but

unsafe struct MyStruct
{
    public fixed bool fs[5];
}

gives a size of 8.

It looks like in fixed bool array, the size of bool element is still 1 byte, but the alignment is 4 bytes. This doesn't match C++ bool array, which is 1 byte size and alignment.

Can someone explain me on this?

Update : I finally find out, the reason is, bool type in a struct, then that struct will NEVER be blittable! So don't expect a struct which has bool type inside to be same layout as in C.

Regards, Xiang.

like image 774
Xiang Zhang Avatar asked Jan 07 '16 05:01

Xiang Zhang


People also ask

What is alignment in C++?

Now, alignment is the method that compilers employ to place variables in the memory, implying that each basic data type is stored at the address divisible by the corresponding size. Usually, alignment is utilized to access data objects faster and efficiently.

What are the alignment requirements for a struct type?

Specify an alignment that's a power of two, such as 1, 2, 4, 8, 16, and so on. Don't use a value smaller than the size of the type. struct and union types have an alignment equal to the largest alignment of any member. Padding bytes are added within a struct to ensure individual member alignment requirements are met.

What is the correct size for alignment in Excel?

You should specify an alignment in the form of a power of two, such as 1, 2, 4, 8, 16, and so on. Also, you must not use a value smaller than the size of the type.

What is the size of a struct in C programming?

The size of a C struct will depend on the members of the struct, their types and how many of them there are. There is really no standard way to force the compiler to make structs to be a multiple of some size. Some compilers provide a pragma that will allow you to set the alignment boundary however that is really a different thing.


1 Answers

A bool is rather special, it goes back to Dennis Ritchie's decision to not give the C language a bool type. That caused plenty of mayhem, language and operating system designers added it themselves and made incompatible choices.

It was added to the Winapi as the BOOL typedef. That's the default marshaling if you don't force another type. Typedef-ed as int to keep it compatible with C, takes 4 bytes as you found out. And aligns to 4, as you found out, like any int does.

It was added to C++. Without a size specification, most C++ compiler implementations chose a single byte for storage. Most notably the Microsoft C++ compiler did, the most likely implementation you'll interop with.

It was added to COM Automation as VARIANT_BOOL. Originally targeted as the new extension model for Visual Basic to get rid of the VBX restrictions, it became wildly popular and just about any language runtime on Windows now supports it. VB back then was heavily affected by 16-bit operating system sensibilities, a VARIANT_BOOL takes 2 bytes.

All three native runtime environments are likely targets for interop in a C# program. Clearly the CLR designers had a very difficult choice to make, having to pick between 1, 2 and 4 bytes. There is no way to win, while the CLR does have a shot at guessing at COM interop, it cannot know whether you try to interop with a C-based api or a C++ program. So they made the only logical choice: none of them.

A struct or class type that contains a bool is never blittable. Not even when you apply [MarshalAs(UnmanagedType.U1)], the one that would make it compatible with the CLR type. Not so sure that was a good decision, it however was the one they made so we'll have to deal with it.

Getting a blittable struct is highly desirable, it avoids copying. It allows native code to directly access the managed heap and stack. Pretty dangerous and many a broken pinvoke declaration has corrupted the GC heap without the usual benefit of the unsafe keyword alert. But impossible to beat for speed.

You get a blittable struct by not using bool. Use byte instead. You can still get the bool back by wrapping the struct member with a property. Don't use an auto-implemented property, you must care about the position of the byte. Thus:

struct MyStruct 
{
    private byte _f;
    public bool f {
        get { return _f != 0; }
        set { _f = value ? 1 : 0; }
    }
}

Native code is oblivious to the property. Don't fret about runtime overhead for the getter and setter, the jitter optimizer makes them disappear and they turn into a single CPU instruction each.

like image 130
Hans Passant Avatar answered Oct 28 '22 22:10

Hans Passant