78

How do I use it in C++? When is it useful to use?

What would be an example of a problem where a bitmask is used to see how it actually works?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Animea Animea
  • 859
  • 2
  • 8
  • 14

4 Answers4

132

Briefly, a bitmask helps to manipulate the position of multiple values. There is a good example here;

Bitflags are a method of storing multiple values, which are not mutually exclusive, in one variable. You've probably seen them before. Each flag is a bit position which can be set on or off. You then have a bunch of bitmasks #defined for each bit position so you can easily manipulate it:

    #define LOG_ERRORS            1  // 2^0, bit 0
    #define LOG_WARNINGS          2  // 2^1, bit 1
    #define LOG_NOTICES           4  // 2^2, bit 2
    #define LOG_INCOMING          8  // 2^3, bit 3
    #define LOG_OUTGOING         16  // 2^4, bit 4
    #define LOG_LOOPBACK         32  // and so on...

// Only 6 flags/bits used, so a char is fine
unsigned char flags;

// Initialising the flags,
// Note that assigning a value will clobber any other flags, so you
// it should generally only use the = operator when initialising variables.
flags = LOG_ERRORS;
// Sets to 1 i.e. bit 0

// Initialising to multiple values with OR (|)
flags = LOG_ERRORS | LOG_WARNINGS | LOG_INCOMING;
// sets to 1 + 2 + 8 i.e. bits 0, 1 and 3

// Setting one flag on, leaving the rest untouched
// OR bitmask with the current value
flags |= LOG_INCOMING;

// Testing for a flag
// AND with the bitmask before testing with ==
if ((flags & LOG_WARNINGS) == LOG_WARNINGS)
   ...

// Testing for multiple flags
// As above, OR the bitmasks
if ((flags & (LOG_INCOMING | LOG_OUTGOING))
         == (LOG_INCOMING | LOG_OUTGOING))
   ...

// Removing a flag, leaving the rest untouched
// AND with the inverse (NOT) of the bitmask
flags &= ~LOG_OUTGOING;

// Toggling a flag, leaving the rest untouched
flags ^= LOG_LOOPBACK;

**

WARNING: DO NOT use the equality operator (i.e. bitflags == bitmask) for testing if a flag is set - that expression will only be true if that flag is set and all others are unset. To test for a single flag you need to use & and == :

**

if (flags == LOG_WARNINGS) //DON'T DO THIS
   ...
if ((flags & LOG_WARNINGS) == LOG_WARNINGS) // The right way
   ...
if ((flags & (LOG_INCOMING | LOG_OUTGOING)) // Test for multiple flags set
         == (LOG_INCOMING | LOG_OUTGOING))
   ...

You can also search C++ Tricks.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
goGud
  • 4,163
  • 11
  • 39
  • 63
  • in your example about bitflags, how does it know which bit belongs to which variable? it's position in the byte, or the actual value of the byte turns on and off certain features? – MarcusJ Jun 01 '15 at 19:38
  • 1
    *"Bitflags are a method of storing..."*, etc. and all of the first code block is copied directly from the source without any clear indication that it is not user "goGud"'s own words. Where is the last part plagiarised from? – Peter Mortensen Aug 26 '22 at 02:35
37

Bit masking is "useful" to use when you want to store (and subsequently extract) different data within a single data value.

An example application I've used before is imagine you were storing colour RGB values in a 16 bit value. So something that looks like this:

RRRR RGGG GGGB BBBB

You could then use bit masking to retrieve the colour components as follows:

  const unsigned short redMask   = 0xF800;
  const unsigned short greenMask = 0x07E0;
  const unsigned short blueMask  = 0x001F;

  unsigned short lightGray = 0x7BEF;

  unsigned short redComponent   = (lightGray & redMask) >> 11;
  unsigned short greenComponent = (lightGray & greenMask) >> 5;
  unsigned short blueComponent =  (lightGray & blueMask);
Dutts
  • 5,781
  • 3
  • 39
  • 61
  • 1
    I don't understand this, you're saying 0xF800 is basically a group of bits that it's selecting from (aka it's extracting those bits from a set group of bytes by address)? I thought a bitmask was basically a int of the same size as the data (so in this case it would be 48 bits) and the mask was applied overtop, when the values of the mask is 1 the value of the underlying bit shows through, and when it's zero, it doesn't, allowing you to ignore the off bits? and what is the shifting for? – MarcusJ Jun 01 '15 at 19:36
  • @MarcusJ: please refer to the example by goGud below, which provides more detail on bitmasks (i.e. http://stackoverflow.com/questions/18591924/how-to-use-bitmask/18592049#18592049) – a505999 Feb 16 '16 at 18:41
  • 1
    I'm an idiot. I knew what bitmasking was, but I didn't realize that the RGB triple wasn't 8 bits each, causing my confusion. thanks for the help though! :) – MarcusJ Feb 17 '16 at 08:36
  • @MarcusJ: RGB triple can be 8 bit for each channel and normally is. However there are some RGB formats where the channels can be less than 8 bits such as 5, 6, 5 so that RGB can be fitted into 16 bits. – Damian Dixon Aug 21 '17 at 05:46
  • Why isn't it symmetric? Why 6 bits for green, but 5 for the other two? – Peter Mortensen Aug 26 '22 at 02:27
  • 1
    @PeterMortensen It can't be symmetric. There are 16 bits available and 3 types of data(RGB). 16/3=5bits for each + 1 bit extra. This is allocated to G in RGB16 format. See https://stackoverflow.com/a/9958424/ and his linked https://multimedia.cx/mmbasics.txt [specifically the section about RGB and YUV colorspaces] – TheMaster Sep 04 '22 at 19:55
7

Let's say I have 32-bit ARGB value with 8-bits per channel. I want to replace the alpha component with another alpha value, such as 0x45

unsigned long alpha = 0x45
unsigned long pixel = 0x12345678;
pixel = ((pixel & 0x00FFFFFF) | (alpha << 24));

The mask turns the top 8 bits to 0, where the old alpha value was. The alpha value is shifted up to the final bit positions it will take, then it is OR-ed into the masked pixel value. The final result is 0x45345678 which is stored into pixel.

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91
6

Bitmasks are used when you want to encode multiple layers of information in a single number.

So (assuming unix file permissions) if you want to store 3 levels of access restriction (read, write, execute) you could check for each level by checking the corresponding bit.

rwx
---
110

110 in base 2 translates to 6 in base 10.

So you can easily check if someone is allowed to e.g. read the file by and'ing the permission field with the wanted permission.

Pseudocode:

PERM_READ = 4
PERM_WRITE = 2
PERM_EXEC = 1

user_permissions = 6

if ((user_permissions & PERM_READ) == PERM_READ) then
  // this will be reached, as 6 & 4 is true
fi

You need a working understanding of binary representation of numbers and logical operators to understand bit fields.

til_b
  • 327
  • 5
  • 15