# Bit-by-bit operations in C++ | Examples

Introduction

Information in a computer is presented in a binary system (presence and absence of voltage). The minimum unit of information is a bit – zero or one, false or true, "no" or "yes". Each byte consists of 8 bits. If **the number is** *signed*, then its leftmost bit denotes the sign of the number - 0 for positive numbers and 1 for negative numbers, the remaining bits form a number module (this applies only to integers, real numbers are always signed). If **the number is** *unsigned*, then all bits are involved in the formation of the value, but the number can only be positive.

Positive integers in a computer are represented in *normal code*, which is the normal representation of a number in a binary system, and negative numbers are *represented in additional code*. To obtain an additional code, a binary representation of an integer modulo equal to a modulo is taken, then all the digits of the binary representation are inverted (0 goes into 1, 1 - 0), while the so-called inverse code is obtained, to which 1 is added to obtain an additional code. For example, the normal code of the number 207 when using 2 bytes is 0000000011001111, and the additional code of the number -207 is 1111111100110001 (the number of digits in the number is significant!). If you add these two numbers, you get 0 (with the transfer of 1 for the higher digit of the number). Adding the positive and negative numbers modulo is the number in the normal code if the result is greater than 0, and the number in the additional code if the result is less than 0.

There are operations that work with bits – you can take negation, apply "AND" or "OR" operations. Bitwise operations apply to enumerations and integral types – bool, char, short, int, and long (possibly with the unsigned modifier). However, you cannot apply these operations to a single bit, but you can only apply the same operation **to all bits of a variable**.

# 1. Operations "negation" ~, "and" &, "or" |, "excluding or"^

# 2. Shift operations

The shift to the right and shift left operations shift the bits in a variable by a specified number of positions. There are three types of shifting:

**logical**– the released bits are filled with zeros both when shifting to the right and when shifting to the left;**arithmetic**– when shifting to the left, the released symbols are filled with zeros, when shifting to the right, the released bits are filled with*the value of the sign*(the leftmost) bit;**cyclic**- the retractable bits are moved to the place of the released ones.

In Assembler, there are all three varieties of shifting, in C++, however, there is only one left shift operation and one right shift operation. When shifting to the left, there is no difference between the arithmetic shift and the logical shift. When shifting to the right, if the variable is *declared as unsigned*, a Boolean shift is performed, while if the variable is declared as signed (the default), an arithmetic shift is performed.

## 3. Examples

**Example 1.** A function that counts the number of single bits in a number

int BitCount(int x)

{int c;

unsigned mask = 0x80000000; // mask is an auxiliary variable, with the help of which one bit is selected from the number

// due to the fact that all bits, except for the leftmost one, will be equal to 0 after applying the & operation,

for (c = 0; x != 0; x <<= 1) // and the leftmost bit will remain unchanged.

if (x & mask) c++; // The variable is initialized with a hexadecimal constant 0x80000000,

return c; // in which all but the leftmost bits are 0.

}

**Example 2.** Function that sets the specified bit to 0

int ClearBit(int x, int pos)

{ unsigned mask = 1;

if (0 <= pos && pos < 32)

return x & (~(mask << pos));

return 0xFFFFFFFF; // In case of error, return a number in which all bits are set to 1

}

Example 3. Function that sets the specified bit to 1

int SetBit(int x, int pos)

{ unsigned mask = 1;

if (0 <= pos && pos < 32)

return x | (mask<<pos);

return 0; // In case of error, return a number in which all bits are set to 0

}

**Example 3.** Function that sets the specified bit to 1

int ClearBit(int x, int pos)

{ unsigned mask = 1;

if (0 <= pos && pos < 32)

return x & (~(mask << pos));

return 0xFFFFFFFF; // In case of error, return a number in which all bits are set to 1

}

Example 3. Function that sets the specified bit to 1

int SetBit(int x, int pos)

{ unsigned mask = 1;

if (0 <= pos && pos < 32)

return x | (mask<<pos);

return 0; // In case of error, return a number in which all bits are set to 0

}

**Example 4.** Using Bitten Operations to Work with Attributes

` #include <cstdio>`

enum Rights // The Rights enumerator names the constants

{ READ = 1, // Use powers of 2 to

WRITE = 2, // so that each constant contains only one 1-bit

MODIFY=4,

DELETE = 8

ALL = 15 // For convenience

};

// Set some permission

void SetRights(unsigned int &user, int r)

{ user |= r; }

// Cancel permission

void UnsetRights(unsigned int &user, int r)

{ user &= ~r; }

void main()

{ unsigned int user1 = 0, user2 = 0;

SetRights(user1, READ | WRITE); // Use the operation | to combine values

SetRights(user2, ALL);

UnsetRights(user2, DELETE);

// Use the & operation to check

if (user1 & READ) printf("User1 can read\n");

if (user1 & WRITE) printf("User1 can write\n");

if (user1 & MODIFY) printf("User1 can modify\n");

if (user1 & DELETE) printf("User1 can delete\n");

if (user2 & READ) printf("User2 can read\n");

if (user2 & WRITE) printf("User2 can write\n");

if (user2 & MODIFY) printf("User2 can modify\n");

if (user2 & DELETE) printf("User2 can delete\n");

}