2

I saw multiple adjacent bit fields while browsing cppreference.

unsigned char b1 : 3, : 2, b2 : 6, b3 : 2;

So,

  • What is the purpose of it?

  • When and where should I use it?

msc
  • 33,420
  • 29
  • 119
  • 214
  • 2
    They're not very useful if they're not adjacent. – molbdnilo Nov 30 '17 at 16:58
  • The main purpose is to define a type that match hardware definition... – Phil1970 Nov 30 '17 at 17:21
  • Possible duplicate of [When to use bit-fields in C?](https://stackoverflow.com/questions/24933242/when-to-use-bit-fields-in-c) – 1201ProgramAlarm Nov 30 '17 at 17:23
  • @1201ProgramAlarm this is c++ question, not c. C and c++ different languages. – msc Nov 30 '17 at 17:25
  • @Phil1970 I don't think that's right. Bitfields are inherently nonportable. To match specific hardware, specific code should be written that guarantees correct addressing, rather than letting the implementation decide how a bitfield looks in memory. – underscore_d Nov 30 '17 at 17:40
  • 1
    @underscore_d Usually for a specific hardware, you have a specific compiler... and when multiple compilers target the same hardware, chances are they define these things the same way. – Phil1970 Nov 30 '17 at 23:56

4 Answers4

1

Obviously, to consume less memory working with bitwise operations. That may be significant for embedded programming, for example.

You can also use std::vector<bool> which can (and usually does) have bitfield implementation.

Anton Malyshev
  • 8,686
  • 2
  • 27
  • 45
  • Why bit manipulation? why not include integers that have a known limited size? – UKMonkey Nov 30 '17 at 16:58
  • @UKMonkey it depends on what do you want to achieve and what limitations you have; some people program in javascript where all numbers are `double` :) – Anton Malyshev Nov 30 '17 at 17:02
  • @AntonMalyshev My point was you say "to consume less memory working with bitwise operations" - it's not just bitwise operations it saves space on. And I'm not sure anyone 'programs' in javascript really, they just type and cry ;) – UKMonkey Nov 30 '17 at 17:04
  • 1
    Might be worth mentioning, bit fields are almost useless outside of embedded or specialized programming situations (in my opinion) as even if you have an object of 4 bits, it still allocates a single byte. Likewise, may not allocate as in intended if you have say 28 bits as it will pad the remaining to 32. – M4rc Nov 30 '17 at 17:05
  • @UKMonkey sure they can consume less memory on their own :) to make good use of them bitwise operations are often handy – Anton Malyshev Nov 30 '17 at 17:09
0
Multiple adjacent bit fields are usually packed together (although this behavior is implementation-defined)

If you want compiler to not add padding or perform structure alignment during multiple bit field allocation you can compile them in a single variable.

struct x
{
  unsigned char b1 : 4;  // compiler will add padding after this. adding to the structure size.
  unsigned char b2 : 3; // compiler will add padding here too!  sizeof(x) is 2.
}


struct y
{
    unsigned char b1 : 4, : 3;   // padding will be added only once.  sizeof(y) is 1
}

Or if you want to allocate bigger bit field in a single variable

struct x
{
    unsigned char b1 :9;   //warning: width of 'x::b1' exceeds its type
};


struct y
{
    unsigned char b1 :6, :3;   //no warning
};
  • 1
    `sizeof(x)` can be 1 for the first case, there is nothing in the standard which mandates it should be 2. – geza Nov 30 '17 at 18:04
  • Quite the opposite. From the C99 standard: "If enough space remains, a bit-field that immediately follows another bit-field in a structure shall be packed into adjacent bits of the same unit". Even if you change the second to `signed char`, the size of the struct is 1 byte. (I've just tested that on MSVC, GCC and Clang, x86, ARM, RISC-V with godbolt) – patstew May 21 '19 at 10:34
  • This answer is all wrong. Even the semicolons after struct are missing. – 0xF Oct 24 '22 at 15:03
0

According to c++draft :

3 A memory location is either an object of scalar type or a maximal sequence of adjacent bit-fields all having nonzero width.[ Note: Various features of the language, such as references and virtual functions, might involve additional memory locations that are not accessible to programs but are managed by the implementation.— end note ]Two or more threads of execution ([intro.multithread]) can access separate memory locations without interfering with each other.

msc
  • 33,420
  • 29
  • 119
  • 214
0

One reason is to reduce memory consumption when you don't need full integer type range. It only matters if you have large arrays.

struct Bytes
{
    unsigned char b1; // Eight bits, so values 0-255
    unsigned char b2;
};
Bytes b[1000000000]; // sizeof(b) == 2000000000

struct Bitfields
{
    unsigned char b1 : 4; // Four bits, so only accommodates values 0-15
    unsigned char b2 : 4;
};

Bitfields f[1000000000]; // sizeof(f) == 1000000000

The other reason is matching binary layout of certain hardware or file formats. Such code is not portable.

0xF
  • 3,214
  • 1
  • 25
  • 29