2

Let's consider this piece of code :

static void Main(string[] args)
{
    Console.WriteLine(Marshal.SizeOf(typeof(bool)));
    Console.WriteLine(String.Join(", ", BitConverter.GetBytes(true)));
}

if bool is 1 byte, I'd expect it to output

1
1

and if bool is 4 bytes (as an int), I'd expect

4
1, 0, 0, 0 // let's forget about the endianness

However, it outputs (in x64)

4
1

That's quite an issue for me in marshaling code. Who should I trust?

Please note that GetBytes takes a boolean as input : enter image description here

canton7
  • 37,633
  • 3
  • 64
  • 77
Regis Portalez
  • 4,675
  • 1
  • 29
  • 41

2 Answers2

5

Both of your ways of measuring the size of a bool are flawed.

Marshal.SizeOf is used to determine how much memory is taken when the given type is marshalled to unmanaged code. A bool is marshalled to a windows BOOL type, which is 4 bytes.

BitConverter.GetBytes(bool) is effectively implemented like this:

public static byte[] GetBytes(bool value) {
    byte[] r = new byte[1];
    r[0] = (value ? (byte)1 : (byte)0 );
    return r;
}

Source.

Therefore it always returns a single-element array.

What you're probably after is sizeof(byte), which "returns the number of bytes occupied by a variable of a given type" (MSDN). sizeof(bool) returns 1.

canton7
  • 37,633
  • 3
  • 64
  • 77
  • Well thanks. Then why the implementation of GetBytes doesn’t match the actual size of the book (when marshaled to unmanaged memory) – Regis Portalez Oct 10 '19 at 12:31
  • 2
    One thing that this doesn't explain is why `Marshal.SizeOf(typeof(char))` returns 1, which leads me to wonder how 2-byte UTF16 chars can be marshalled in a single byte without potential data loss... – Matthew Watson Oct 10 '19 at 12:34
  • 1
    @Matthew Compatibility with Win9x and ANSI, [apparently](https://github.com/dotnet/corefx/issues/39641#issuecomment-513441958). The actual runtime marshalling code is a lot smarter than this: it knows to call the right xxxA/xxxW overload, and marshal strings accordingly, etc. – canton7 Oct 10 '19 at 12:37
  • @Regis `BitConverter` has nothing to do with marshalling types to unmanaged code - they're entirely separate. `BitConverter` does its own thing. It can re-interpret things it's written, given that you're running on a machine with the same endianness, but it relies on various details (like endianness, that floating-point is implemented in a particular way, etc) – canton7 Oct 10 '19 at 12:41
0

The case here is that Marshal.SizeOf returns the size of an unmanaged type in bytes and unmanaged equivalent of boolean is a 4-byte Win32 BOOL type. see https://stackoverflow.com/a/6420546/3478025 for details

Hubert
  • 343
  • 5
  • 10