0

I am working on a networking application where I will receive 2 bytes and certain bits have specific significance. I am trying to implement that packet as a structure. The intent is to do a binary copy to object address and the fields of the packet are ready to be accessed. Here is a simple example representing my problem. When we try to inspect the size of the bitfield and structure they are not coming as expected.

#include <bitset>
#include<iostream>
struct a
    {
        std::bitset<8> b;
        uint8_t c;

    };
int main()
{
    std::cout<<sizeof(a);
}

Output: 8

Expected Output: 2

Is this something specific to Bitset's implementation?

Generally, each element occupies only one bit (which, on most systems, is eight times less than the smallest elemental type: char). (ref- cplusplus.com/reference/bitset/bitset/ )

compiled on Microsoft Visual Studio 2019 16.10.2

  • 1
    I expected `std::bitset` to have a saner implementation... You can either use another `uint8_t`, or use the actual bitfields, e.g. `uint8_t foo:1, bar:1;`. – HolyBlackCat Jul 22 '21 at 06:14
  • The problem is that for some reason `sizeof(std::bitset<8>) == 8`, it is unrelated to the class https://godbolt.org/z/Mhd1n7TYK . Maybe it is because efficiency, in some systems could be faster to implement 8-bits (or even less) operations with an underlying 8 byte type? The good news is that `sizeof(std::bitset<64>) == 8` and not 64. – alfC Jul 22 '21 at 10:30

1 Answers1

1

The source code of Microsoft Visual Studio' STL is open-sourced recently, you can check the implementation of bitset here, we can confirm that the data structure is an array, the sketch:

template <size_t _Bits>
class bitset { // store fixed-length sequence of Boolean elements
public:
    using _Ty = conditional_t<_Bits <= sizeof(unsigned long) * CHAR_BIT, unsigned long, unsigned long long>;
    static constexpr ptrdiff_t _Bitsperword = CHAR_BIT * sizeof(_Ty);
    static constexpr ptrdiff_t _Words       = _Bits == 0 ? 0 : (_Bits - 1) / _Bitsperword; // NB: number of words - 1
    _Ty _Array[_Words + 1];
};

So for std::bitset<8>, the underly array is unsigned long _Array[1]. Then we get the size: 4. For the result of sizeof struct a we get 8, this is caused by the alignment around b and c, please see this answer for reference about alignment.

As you are dealing with network applications, it's not suitable to use bitset here. To decode network protocol, it's better to use bit fields. There is a good example in seastar's tcp decoder, you may take it as an example.

prehistoricpenguin
  • 6,130
  • 3
  • 25
  • 42
  • 3
    `sizeof(unsigned long)` in Microsoft's compiler is 4 bytes, not 8 bytes. The extra bytes are more likely coming from alignment padding. The struct needs to be set to 1-byte alignment to eliminate padding. – Remy Lebeau Jul 22 '21 at 07:03
  • @RemyLebeau Thanks for the great comment! I just forget the difference between Gcc and VC++. I have updated the answer now. – prehistoricpenguin Jul 22 '21 at 07:20
  • 2
    the alignment padding is more likely after the `c` field, rather than between the `b`and `c` fields. You can use `offsetof(a::c)` to verify that. – Remy Lebeau Jul 22 '21 at 07:27
  • @RemyLebeau I have confirmed that the padding is after c field! Thanks for so many great suggestions! – prehistoricpenguin Jul 22 '21 at 07:31