-1

I have this simple struct with sum of it's fields = 10 bits

public struct TestSTrut
{
    public byte ByteField;
    public bool BoolFieldOne;
    public bool BoolFieldTwo;

    public TestSTrut(byte a, bool b, bool c)
    {

        ByteField= a;
        BoolFieldOne= b;
        BoolFieldTwo= c;
    }

}

Now if i put 1000 of those in array the array is 3012 bytes in size which means each struct is 3 bytes ? but is should be 1250 bytes ? (10*1000) / 9.

If I put 1000 bytes in an array for comparison it's 1012 bytes in size (12 bytes for array overhead).

I am testing this using Visual studio in debug in x64

IronHide
  • 327
  • 1
  • 3
  • 17
  • how can you arrange 1 bit of memory? – vasily.sib Jul 25 '19 at 09:47
  • @vasily.sib The two bool fields could be packed into a single byte (but aren't). – AKX Jul 25 '19 at 09:47
  • Read about [memory alignment](https://stackoverflow.com/q/381244/4685428) – Aleks Andreev Jul 25 '19 at 09:48
  • 2
    The minimum size of a field in a struct is a byte not a bit - so the struct size is 3 bytes. – PaulF Jul 25 '19 at 09:48
  • Note that despite being 3 bytes, depending on how the compiler decides to pack the struct - it may occupy more space. https://kalapos.net/Blog/ShowPost/DotNetConceptOfTheWeek13_DotNetMemoryLayout – PaulF Jul 25 '19 at 09:55
  • 1
    Struct alignemnt will be 1 byte (so 8 bits), now 8 bit will take 8 bits, then bool will be written at 9th bit, because there is no need for alignemnt, next bit needs to be alignet, so there will be 7 bits offset, and on 17th bit another bool will be written. And it will align to 24 bits adding another 7 empty bits of offset. Giving 3 bytes in size. – Michał Turczyn Jul 25 '19 at 09:57
  • there is still possible to pack this 2 `bool`s to `[Flags]` enum – vasily.sib Jul 25 '19 at 10:53

1 Answers1

2

The simple answer:

sizeof(bool) == 1

If you need a more compact storage, you need to write your own.

Luaan
  • 62,244
  • 7
  • 97
  • 116
  • 1
    [BitVector32](https://learn.microsoft.com/en-us/dotnet/api/system.collections.specialized.bitvector32), [BitArray](https://learn.microsoft.com/en-us/dotnet/api/system.collections.bitarray)? – Sinatr Jul 25 '19 at 09:51
  • @Sinatr Yep, but that already means you need some logic to work with the arrays - using an array of structs, each with its own `BitArray` is probably worse than having those two bools. So you'd probably have something like "a BitArray of bool1's, a BitArray of bool2's, an array of byte's". But that depends entirely on what the OP is trying to do - it doesn't seem like he has a problem that needs to be solved, just a bit of curiosity. – Luaan Jul 25 '19 at 09:53
  • I had no idea about that wow, but why ? It's such a was of memory :( – IronHide Jul 25 '19 at 09:58
  • @IronHide Trade-offs. Working with memory on a bit-per-bit level is rather expensive. Memory is much cheaper and easier to expand than CPU time (and memory access time) nowadays, so unless you have a good reason not to, you want to keep things simple. That means memory alignment and other related things. Some languages do the packing for you (though the struct as a whole will still be rounded to the nearest integer size - so in your case, it'd be 2 bytes instead of 3 bytes; unless it's aligned to 4 bytes or 8 bytes anyway :P), C# doesn't. – Luaan Jul 25 '19 at 10:15
  • @IronHide In the end, if you need to have lots of booleans compared to other data, you need to think about your design in more detail anyway. You want to be very explicit about how you handle the bools. You might want to use bit arrays or flag enums, or any number of other solutions. C# just doesn't try to second-guess you :) – Luaan Jul 25 '19 at 10:17
  • @Luaan my top priority is memory usage, as it will be used for BFS search, I am looking at BitVector and BitArray but I could just suin ushort[] instead, and just do bit manipulations to extract what I need, just wondering if BitArray or BitVector would take less memory than ushort[] and how easy could i extract the data using BitArray or BitVector e.g teh ByteField stores Id of some data form 0 to 255, does BitArray or BitVector provide easy way to convert it's section to e.g byte ? – IronHide Jul 25 '19 at 10:26
  • @IronHide `BitArray` is a class; you need to take that into account. It's designed for easy use, and works best if you can pack as much data as you can into one `BitArray`. It can be built over arrays of bool, byte or int, and copied to them as well, so it's pretty easy to get from one representation to another (each int in the array corresponds to 32 bits, each byte to 8 bits, each bool to 1 bit). `BitVector` is a struct that does what you'd do manually with an `uint` (there's two variants, one 4 byte, another 8 byte). Flag enums are useful if the bits have meaning - they can be byte-sized. – Luaan Jul 25 '19 at 10:31
  • @Luaan well if I need max 10 bits, then i think the least amount of space used will be achieved using ushort (16 bits, 6 wasted), BitArray will have already too much overhead just for being class, and BitVector is 32 bits minimum. – IronHide Jul 25 '19 at 10:43
  • @IronHide If you need it as a field in a struct, yes. Though if you can access the bits based on a name rather than plain index, I'd recommend a flag enum based on short. Another alternative would be having the logical structure separate from the physical structure - have one large `BitArray` that contains the bit data for all your records, and you avoid wasting those 6 bits. Depends entirely on what you're trying to do :) – Luaan Jul 25 '19 at 10:50