0

I played with https://gcc.godbolt.org/ and this code seems to always return 1.

However I wonder if standard guarantee this.

#include <cstdint>

struct S{
   uint8_t a : 6;
   uint8_t b : 2;
};

int main(){
    return sizeof(S);
}

My real example is following:

struct Pair{
    uint64_t    created;    // 8 bytes
    uint32_t    expires;    // 4 bytes
    uint16_t    keylen;     // 2 bytes, 4 bits are used for vallen. 2 bits are reserved for future versions. 10 bytes for keylen.
    uint16_t    vallen;     // 2  bytes
};

Currently I do some bitmasks and shifts.

Can I do it like this? Will it always work (any "normal" compiler)?

How keylen behave on Big Endian? Using shifts I always use first 4 bits.

struct Pair{
    uint64_t    created;
    uint32_t    expires;
    uint8_t     vallen2 : 4;
    uint8_t     future  : 2;
    uint16_t    keylen  : 10;
    uint16_t    vallen; 
};
Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
Nick
  • 9,962
  • 4
  • 42
  • 80
  • Does this answer your question? [Force C++ structure to pack tightly](https://stackoverflow.com/questions/21092415/force-c-structure-to-pack-tightly) – super Sep 22 '20 at 07:36
  • `struct __attribute__ ((packed))` packs align. I am asking for "bit fields" – Nick Sep 22 '20 at 07:45
  • To quote [cppreference](https://en.cppreference.com/w/cpp/language/bit_field#:~:text=bit%20fields&text=Declares%20a%20class%20data%20member,and%20straddle%20the%20individual%20bytes.&text=The%20type%20of%20the%20bit,seq%20of%20the%20declaration%20syntax.&text=an%20integral%20constant%20expression%20with%20a%20value%20greater%20or%20equal%20to%20zero.) : `Multiple adjacent bit fields are usually packed together (although this behavior is implementation-defined)`. You could add a `static_assert` to check that your 2 versions of `Pair` given here gives you the same `sizeof` maybe. – super Sep 22 '20 at 08:00
  • Like [this](https://godbolt.org/z/Ybbn4K). – super Sep 22 '20 at 08:07
  • @super - so it is not guaranteed. Thanks. Made it as answer so I can accept it. – Nick Sep 22 '20 at 10:11
  • 1
    If you want to have control about how bits are packed, I advise you to use a bitmask, since 1B is the minimum addressable value. In this way, you don't have to care about how the compiler is optimizing the memory and how it re-aligns bits then. I also add that this is often not something you should care about, except in some edge cases – Christian Vincenzo Traina Sep 22 '20 at 10:48
  • @cristian - this is exactly what I am doing currently. – Nick Sep 22 '20 at 13:18
  • 1
    @Nick sorry, hadn't seen that – Christian Vincenzo Traina Sep 22 '20 at 15:00

1 Answers1

1

Most compilers will give you bit fields that are packed together, although the behaviour is implementation defined.

One way to check would be to add a static_assert to compare the size of your struct definitions with and without the bitfields. This way you would get a nice compile time error once the implementation doesn't do what you expect.

#include <cstdint>

struct Pair_size_check{
    uint64_t    created;    // 8 bytes
    uint32_t    expires;    // 4 bytes
    uint16_t    keylen;     // 2 bytes, 4 bits are used for vallen. 2 bits are reserved for future versions. 10 bytes for keylen.
    uint16_t    vallen;     // 2  bytes
};

struct Pair{
    uint64_t    created;
    uint32_t    expires;
    uint8_t     vallen2 : 4;
    uint8_t     future  : 2;
    uint16_t    keylen  : 10;
    uint16_t    vallen; 
};

static_assert(sizeof(Pair) == sizeof(Pair_size_check));
super
  • 12,335
  • 2
  • 19
  • 29