In Solidity, bitwise operators are used to perform operations on individual bits of data types such as uint
, int
, and bytes
. These operations are often used in low-level programming, such as optimizing storage or performing calculations on flags, masks, or packed data.
Here are the main bitwise operators in Solidity:
1. AND (&
)
The bitwise AND operator compares corresponding bits of two operands and returns 1
if both bits are 1
, otherwise, it returns 0
.
uint8 a = 5; // 0101 in binary
uint8 b = 3; // 0011 in binary
uint8 result = a & b; // 0001 in binary (result is 1)
2. OR (|
)
The bitwise OR operator compares corresponding bits of two operands and returns 1
if at least one of the bits is 1
, otherwise, it returns 0
.
uint8 a = 5; // 0101 in binary
uint8 b = 3; // 0011 in binary
uint8 result = a | b; // 0111 in binary (result is 7)
3. XOR (^
)
The bitwise XOR (exclusive OR) operator compares corresponding bits of two operands and returns 1
if the bits are different, and 0
if they are the same.
uint8 a = 5; // 0101 in binary
uint8 b = 3; // 0011 in binary
uint8 result = a ^ b; // 0110 in binary (result is 6)
4. NOT (~
)
The bitwise NOT operator inverts the bits of its operand. It flips each 1
to 0
and each 0
to 1
.
uint8 a = 5; // 0101 in binary
uint8 result = ~a; // 11111010 in binary (result is 250 in unsigned 8-bit representation)
Note that Solidity uses two’s complement for signed integers, so the result might be negative for signed types.
5. Left Shift (<<
)
The left shift operator shifts the bits of the operand to the left by the specified number of positions. It effectively multiplies the operand by 2^n
, where n
is the number of positions.
uint8 a = 5; // 0101 in binary
uint8 result = a << 1; // 1010 in binary (result is 10)
6. Right Shift (>>
)
The right shift operator shifts the bits of the operand to the right by the specified number of positions. It effectively divides the operand by 2^n
, where n
is the number of positions.
uint8 a = 5; // 0101 in binary
uint8 result = a >> 1; // 0010 in binary (result is 2)
For signed integers, Solidity uses arithmetic right shift for signed types (int
), which preserves the sign bit.
7. Signed Right Shift (>>
) for Signed Integers
When applied to signed integers, the right shift operator preserves the sign bit (most significant bit) for negative numbers.
int8 a = -5; // 11111011 in two's complement
int8 result = a >> 1; // 11111101 in two's complement (result is -3)
Practical Use Cases
- Flag management: Bitwise operations are often used to set, clear, or toggle flags stored in a single variable.
- Data compression: Storing multiple small data elements in a single larger variable using bitwise operators to mask or extract them.
- Efficient calculations: Shifting bits to multiply or divide by powers of 2 instead of using multiplication or division operators.
Example: Using Bitwise Operators to Set and Check Flags
pragma solidity ^0.8.0;
contract BitwiseExample {
uint8 public flags;
// Set a specific flag
function setFlag(uint8 flagPosition) public {
flags |= (1 << flagPosition); // Set the bit at position `flagPosition` to 1
}
// Clear a specific flag
function clearFlag(uint8 flagPosition) public {
flags &= ~(1 << flagPosition); // Set the bit at position `flagPosition` to 0
}
// Check if a specific flag is set
function isFlagSet(uint8 flagPosition) public view returns (bool) {
return (flags & (1 << flagPosition)) != 0; // Return true if the bit at `flagPosition` is 1
}
}
In this example:
setFlag
: Sets the bit at a specific position to 1
.
clearFlag
: Clears the bit at a specific position, setting it to 0
.
isFlagSet
: Checks if the bit at a specific position is 1
.
Bitwise operators allow for compact and efficient representation and manipulation of multiple flags or small data elements within a single variable.