# Bit-Wise Expressions

- Classify bit-wise operation order among other operations
- Describe how to access and manipulate the individual bits of a type
- Declare bit fields in a class type

"C [and hence C++] has an unusually rich set of operators that provide access to most of the operations provided by the underlying hardware." Harbison and Steele (2002)

Bit-wise expressions provide the mechanism for accessing individual bits within a type and creating new values by operating on the individual bits of the operands. Each bit-wise expression has its own value and type. The C++ bit-wise operators define the language facilities for accessing and manipulating the bits within the bytes of integral and enumerated types. These operators follow the rules of precedence of the language.

This chapter completes the chapter entitled Expressions by reviewing the precedence rules for the bit-wise operators and describing the bit-wise expressions that C++ supports on integral and enumerated types. This chapter also shows how to declare bit fields in a class type.

## Operator Precedence

### Order of Evaluation

A compound expression evaluates according to rules defined through the precedence table below. These rules cannot be changed. The compiler evaluates the expression with the operator that has a higher precedence before evaluating any other expression. Some operators associate from left to right, while other operators associate from right to left.

Precedence | Class | Operator | Description | Associates |
---|---|---|---|---|

18 | primary | name, literal | ||

18 | binary | `::` | scope resolution | |

17 | postfix | `[]` | array subscripting | left-to-right |

17 | postfix | `( )` | function call | left-to-right |

17 | postfix | `.` | direct selection | left-to-right |

17 | postfix | `->` | indirect selection | left-to-right |

17 | postfix | `++` `--` | postfix increment, decrement | left-to-right |

17 | postfix | `typeid()` | type name | left-to-right |

17 | postfix | `const_cast` | constant type conversion | left-to-right |

17 | postfix | `dynamic_cast` | dynamic type conversion | left-to-right |

17 | postfix | `reinterpret_cast` | reinterpreted type conversion | left-to-right |

17 | postfix | `static_cast` | static type conversion | left-to-right |

16 | prefix | `++` `--` | prefix increment, decrement | right-to-left |

16 | unary | `sizeof` | size | right-to-left |

16 | unary | `!` | logical negation | right-to-left |

16 | unary | `~` | bit-wise negation | right-to-left |

16 | unary | `-` `+` | arithmetic negation, plus | right-to-left |

16 | unary | `&` | address of | right-to-left |

16 | unary | `*` | indirection | right-to-left |

16 | unary | `new` `new[]` | dynamic memory allocation | right-to-left |

16 | unary | `delete` `delete[]` | dynamic memory deallocation | right-to-left |

16 | unary | `alignof(type)` | alignment requirement | right-to-left |

16 | unary | `noexcept()` | controls exception throwing | right-to-left |

16 | unary | `(type)` | type casting | right-to-left |

15 | binary | `.*` | object to member pointer | left-to-right |

15 | binary | `->*` | pointer to member pointer | left-to-right |

14 | binary | `*` `/` `%` | multiplicative | left-to-right |

13 | binary | `+` `-` | additive | left-to-right |

12 | binary | `<<` `>>` | left and right bit shifting | left-to-right |

11 | binary | `<` `>` `<=` `>=` | relational | left-to-right |

10 | binary | `==` `!=` | equality, inequality | left-to-right |

9 | binary | `&` | bit-wise logical and | left-to-right |

8 | binary | `^` | bit-wise logical exclusive or | left-to-right |

7 | binary | `ǀ` | bit-wise logical or | left-to-right |

6 | binary | `&&` | logical and | left-to-right |

5 | binary | `ǀǀ` | logical or | left-to-right |

4 | ternary | `?:` | conditional | right-to-left |

3 | binary | `=` `+=` `-=` `*=` `/=` `%=` | compound type-wise assignment | right-to-left |

3 | binary | `~=` `&=` `^=` `ǀ=` `>>=` `<<=` | compound bit-wise assignment | right-to-left |

2 | unary | `throw` | transfers control to exception handler | left-to-right |

1 | binary | `,` | sequencing | left-to-right |

To override the order defined in this table, we enclose the expressions to be evaluated first within parentheses.

## Unary Expression

### Bit-Wise Negation

The bit-wise negation operator (`~`

) converts its operand to its one's complement. The operand may be of integral or unscoped enumerated type. The result of the operation is a *prvalue*.

For instance, applying the negation operator to the following bit pattern

`01011001 11001101 11101011 11100010`

yields

`10100110 00110010 00010100 00011101`

The following program yields the output shown below:

`// Bitwise Expressions - Negation`

// negation.cpp

#include <iostream>

#include <iomanip>

using namespace std;

typedef unsigned char uc;

typedef signed char sc;

typedef unsigned short us;

typedef signed short ss;

typedef unsigned int ui;

typedef signed int si;

int main ()

{

ui u = 27u;

us s = (us)27u;

uc c = (uc)27;

si i = 27;

ss t = (ss)27;

sc d = (sc)27;

cout << "u:" << u << ",~u:" << setw(10) << ~u

<< ",~~u:" << setw(3) << ~~u << endl;

cout << "s:" << s << ",~s:" << setw(10) << (us)~s

<< ",~~s:" << setw(3) << ~~s << endl;

cout << "c:" << (ui)c << ",~c:" << setw(10) << (ui)(uc)~c

<< ",~~c:" << setw(3) << ~~c << endl;

cout << "i:" << i << ",~i:" << setw(10) << ~i

<< ",~~i:" << setw(3) << ~~i << endl;

cout << "t:" << t << ",~t:" << setw(10) << ~t

<< ",~~t:" << setw(3) << ~~t << endl;

cout << "d:" << (si)d << ",~d:" << setw(10) << ~d

<< ",~~d:" << setw(3) << ~~d << endl;

}

`u:27,~u:4294967268,~~u:27`

s:27,~s: 65508,~~s:27

c:27,~c: 228,~~c:27

i:27,~i: -28,~~i:27

t:27,~t: -28,~~t:27

d:27,~d: -28,~~d:27

Negation is self-inverting: the negation of the negation of a value is the original value.

The negation of an `unsigned`

variable is the largest number that an `unsigned`

type can store less its original value.

### Good Design Practice

Representation of negative integers is not defined in the language standard and different platforms may use different rules. Since the result of a bit-wise negation on a `signed`

integral value is not fully portable, it is better to limit the use of bit-wise negation expressions to `unsigned`

integral types.

## Binary Expressions

Binary expressions consist of two operands and one operator. They include bit-shifting, bit-wise and, bit-wise or and bit-wise exclusive or operators. They evaluate to *prvalues*.

### Bit-Shifting

Bit-shifting expressions shift the bit pattern of the left operand towards its left or right end. The right operand specifies the number of bit positions by which to shift the pattern. The left operand is of integral or unscoped enumeration type. The right operand is of integral or unscoped enumeration type and non-negative in value. The expression evaluates to the result, is of the same type as the left operand, and is a *prvalue*.

#### Left-Shift Operator

The left-shift operator (`<<`

) shifts the bits in the left operand to the left by the value of the right operand and fills the vacated bits with 0 values.

For example,

`// Bitwise Expressions - Left Shift`

// left.cpp

#include <iostream>

int main ()

{

unsigned u = 27u; // 0...00011011

std::cout << u << " << " << 2 << " = " << (u << 2) << std::endl;

}

`27 << 2 = 108`

For an `unsigned`

left operand, the result is the left operand multiplied by 2 to the power of the right operand.

#### Right-Shift Operator

The right-shift operator (`>>`

) shifts the bits in the left operand to the right by the value of the right operand and fills the vacated bits with the value of the highest order bit.

For example,

`// Bitwise Expressions - Right Shift`

// right.cpp

#include <iostream>

#include <climits>

int main ()

{

unsigned u, v;

int w;

u = 27u; // 0...0011011

v = 1u << sizeof(unsigned) * CHAR_BIT - 1; // 10..0000000

w = -1; // 1...1111111

std::cout << u << " >> " << 2 << " = " << (u >> 2) << std::endl;

std::cout << v << " >> " << 8 << " = " << (v >> 8) << std::endl;

std::cout << w << " >> " << 2 << " = " << (w >> 2) << std::endl;

}

`27 >> 2 = 6`

2147483648 >> 8 = 8388608

-1 >> 2 = -1

`CHAR_BIT`

holds the number of bits in a byte and is defined in `<climits>`

.

For an `unsigned`

left operand, the result is the left operand divided by 2 to the power of the right operand.

#### Multiplying and Dividing by Powers of 2

Bit-shifting expressions provide fast multiplication or division by powers of 2. That is,

`27 << 0 is equal to 27 * 1 = 27 // 0...00011011`

27 << 1 is equal to 27 * 2 = 54 // 0...00110110

27 << 2 is equal to 27 * 4 = 108 // 0...01101100

27 << 3 is equal to 27 * 8 = 216 // 0...11011000

and

`27 >> 0 is equal to 27 / 1 = 27 // 0...00011011`

27 >> 1 is equal to 27 / 2 = 13 // 0...00001101

27 >> 2 is equal to 27 / 4 = 6 // 0...00000110

27 >> 3 is equal to 27 / 8 = 3 // 0...00000011

### Bit-Wise and

The bit-wise 'and' operator (`&`

) compares every bit of the left and right operands and returns a value of the same type that consists of the bit by bit results of the comparison. The operands are of integral or unscoped enumeration type. The rules for an 'and' comparison are:

- if both bit values are 1, the resultant bit value is 1
- otherwise, the resultant bit value is 0

#### Masking

We can use bit-wise 'and' expressions to extract individual bits from a variable. Consider the following two operands:

`01011001 11001101 11101011 11100010`

00000000 00000000 00001111 00000000

The bit-wise 'and' operator applied to these two operands yields the following result

`00000000 00000000 00001011 00000000`

That is, we retrieve the 8th-11th bit values (the rightmost bit being bit 0) of the left operand. The right operand ignores all but bits 8 through 11. We call the operand that defines the bits to extract the *mask*.

The following example yields the output shown below

`// Bit-wise and`

// and.cpp

#include <iostream>

int main ()

{

unsigned char u = 27u; // 00011011 = 27

unsigned char v = 14u; // 00001110 = 14 - mask

// -------------

// 00001010 = 10

std::cout << (unsigned)u << " & " << (unsigned)v << " = " << (u & v) << '\n';

}

`27 & 14 = 10`

The parentheses are necessary since the insertion operator (`<<`

) is of higher precedence than the bit-wise 'and' operator.

#### Oddness Test

The bit-wise 'and' operator with a right operand of 1 returns the oddness of the left operand:

`bool odd = (bool)(value & 1)`

`odd`

has the value `true`

if value is odd, `false`

if value is even.

#### Fast Remainder

The bit-wise 'and' operator can extract the remainder of a division by powers of 2 more efficiently than the modulus operator. The bit-wise 'and' expression on a left operand with the right operand set to one less than the divisor gives the remainder directly

`unsigned char u = 27u; // 00011011`

27 & (1 - 1) is equal to 00000000 or 0 which is 27 % 1

27 & (2 - 1) is equal to 00000001 or 1 which is 27 % 2

27 & (4 - 1) is equal to 00000011 or 3 which is 27 % 4

27 & (8 - 1) is equal to 00000011 or 3 which is 27 % 8

### Bit-Wise or

The bit-wise 'or' operator (`|`

) compares every bit of the left and right operands and returns a value of the same type that is the bit by bit result of the comparison. The operands are of integral or unscoped enumeration type. The rules for an 'or' comparison are:

- if either bit value is 1, the resultant bit value is 1
- otherwise, the resultant bit value is 0

#### Turn-on a Bit

A bit-wise 'or' expression can turn on an individual bit or a set of bits in a variable. Consider the following two operands:

`01011001 11001101 11101011 11100010`

00000000 00000000 00001111 00000000

The bit-wise 'or' operator applied to these operands yields the result

`01011001 11001101 11101111 11100010`

The following program produces the output shown below:

`// Bit-wise or`

// or.cpp

#include <iostream>

int main ()

{

unsigned char u = 27u; // 00011011 = 27

unsigned char v = 14u; // 00001110 = 14

// -------------

// 00011111 = 31

std::cout << (unsigned)u << " | " << (unsigned)v << " = " << (u | v) << '\n';

}

`27 | 14 = 31`

### Bit-Wise Exclusive or

The bit-wise 'exclusive or' operator (`^`

) compares every bit of the left and right operands for exclusivity. The operands are of integral or unscoped enumeration type. The rules for an 'exclusive-or' comparison are:

- if the bit values are different, the resultant bit value is 1
- if the bit values are the same, the resultant bit value is 0

#### Flipping Selected Bits

A bit-wise 'exclusive or' expression to flip an individual bit or a set of bit values in a variable. Consider the following two operands:

`01011001 11001101 11101011 11100010`

00000000 00000000 00001111 00000000

The bit-wise 'exclusive-or' operator applied to these operands yields the result:

`01011001 11001101 11100100 11100010`

The following program produces the output shown below:

`// Bitwise Exclusive or`

// xor.cpp

#include <iostream>

int main ()

{

unsigned char u = 27u; // 00011011

unsigned char v = 14u; // 00001110

// --------

// 00010101

std::cout << (unsigned)u << " ^ " << (unsigned)v << " = " << (u ^ v) << '\n';

std::cout << (unsigned)u << " ^ " << (unsigned)v << " ^ " << (unsigned)v

<< " = " << (u ^ v ^ v) << '\n';

}

`27 ^ 14 = 21`

27 ^ 14 ^ 14 = 27

The 'exclusive or' operator is self-inverting.

### Assignment Expressions

An assignment expression copies from the right operand to the left one. The left operand must be a modifiable lvalue. Assignment expressions associate from right to left, which enables cascading. They may be simple or compound.

#### Compound Assignment

The compound operators (`>>=`

, `<<=`

, `~=`

, `&=`

, `|=`

, `^=`

) perform the operation specified by the first character(s) in the operator on the two operands before copying the result into the left operand.

## Bit Fields

A member declaration of a class type can include a bit field. C++ lets us allocate a specific number of bits to a data member, provided that that member is of integral or unscoped enumeration type. The declaration of a bit field takes the form

`Type identifier : constant-expression;`

`constant-expression`

is positive-valued and specifies the number of bits to be allocated. C++ does not allow a non-`const`

reference to a bit field.

To include bit-padding between adjacent data members, we insert an unnamed bit field that specifies the number of padding bits:

`class A`

{

unsigned a : 5;

unsigned : 3; // padding

unsigned b : 6;

};

To ensure alignment of the next member at an alignment boundary, we insert a bit field of 0:

`class A`

{

unsigned a : 5;

unsigned : 0; // align b at alignment boundary

unsigned b : 6;

};

Bit-field allocation is implementation defined. Packing strategies are typically implementation-dependent and not portable. Each platform has

- its own constraints on the alignment of bit fields and members
- its own maximum size that a bit field cannot exceed
- its own method of packing several bit fields

## Exercises

- Read the Wikipedia article on Bit-wise operations