39

How are boolean variables in C# stored in memory? That is, are they stored as a byte and the other 7 bits are wasted, or, in the case of arrays, are they grouped into 1-byte blocks of booleans?

This answers the same question regarding Java (Why is Java's boolean primitive size not defined?). Are Java and C# the same in this regard?

Community
  • 1
  • 1
  • Regarding the "and the other 7 bits are wasted" - yes they are. Although it depends the language _how_ they are wasted: C# value `true` wastes the 7 additional bits with zeros whereas VB.NET value `true` wastes them with ones (although you never have to know, .NET treats everything non-zero as true). – Christoph Dec 10 '19 at 09:47
  • I withdraw my statement from above: When I wrote a type to demonstrate that behavior I found out that VB.NET currently (.NET 4.8) also only sets the lowest bit for `true`. (I didn't investigate further if the behavior was different in the past or if I was totally mistaken - feel free to leave a comment if you know more about it). The statement that ".NET treats everything non-zero as true" I could confirm with my tests. – Christoph Dec 13 '19 at 08:57

2 Answers2

37

In C#, certainly the bits aren't packed by default, so multiple bool fields will each take 1 byte. You can use BitVector32, BitArray, or simply bitwise arithmetic to reduce this overhead. As variables I seem to recall they take 4 bytes (essentially handled as int = Int32).

For example, the following sets i to 4:

struct Foo
{
    public bool A, B, C, D;
}
static unsafe void Main()
{
    int i = sizeof(Foo);
}
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 10
    Note that trying to optimize this stuff is most likely premature. Unless you primarily operate on huge amounts of boolean data, they won't be the cause of any memory problems. – Anon. Feb 22 '10 at 00:17
  • But if you use `Marshal.SizeOf` with an instance of `Foo`, it returns 16, whether it's a class member or a local variable (as per Stilgar's answer). – Andrew Sep 04 '15 at 14:48
  • 3
    @Andrew what `Marshal` returns is largely unrelated, frankly. Unless you are actually using marshaling, that is. – Marc Gravell Sep 04 '15 at 15:00
  • Does this imply that using `bool` has only a semantic advantage over `byte`? If so, then you can make multiple state variables for the exact price of a 2 state var. – mireazma Jan 23 '18 at 11:38
  • 2
    @mireazma if you were dealing with state flags, your best bet is a flags enum - then they will be packed at the bit level – Marc Gravell Jan 23 '18 at 12:13
  • 2
    That 4 bool use 16 bytes is related to the pack size of the struct. If you use `[StructLayout(LayoutKind.Sequential, Pack = 1)]` it _should_ be packed into 4 bytes... – Christoph Dec 10 '19 at 09:40
20

In C# they are stored as 1 byte in an array or a field but interestingly they are 4 bytes when they are local variables. I believe the 1-byteness of bool is defines somewhere in the .NET docs unlike Java. I suppose the reason for the 4 bytes for local variables are to avoid masking the bits when readng 32bits in a register. Still the sizeof operator shows 1 byte because this is the only relevant size and everything else is implementation detail.

Stilgar
  • 22,354
  • 14
  • 64
  • 101
  • 1
    A float? gets stored as a float and a bool, and the bool's end up 4 bytes in this case as well (float? takes 8 bytes vs. 4 for a float). Maybe it aligns the bools to 4 bytes in this case since it is paired with a float in the array. – John Fairbanks Feb 14 '14 at 17:13
  • @John, how did you measure `float?`'s size? I can't use `sizeof` and `Marshal.SizeOf` returns 4. – Andrew Sep 04 '15 at 14:43
  • 1
    I created a float?[] and a float[]. Before and after each step, I called GC.GetTotalMemory(). If you call GC.Collect() a couple of times prior to the GetTotalMemory call you will see the actual amount of memory consumed by the allocation including any alignments, not just the size of the data element itself. – John Fairbanks Sep 04 '15 at 18:49