Bitwise Operators in Go
This article covers bitwise operators in Go, their functions, and practical uses in cryptography, networking, and optimization.
Join the DZone community and get the full member experience.
Join For FreeIn low-level programming, it is common to work at the bit level. This was true in earlier days of computing and is even relevant today. Most popular languages keep provisions for bit-level operations, not only as a legacy but also as a frequently used feature in their arsenal. Direct bit-level operations are used in cryptography, system-level programming, image processing, etc. In this Golang programming tutorial, we will go into the details of bitwise operators and how to work with them in Go.
Golang Bitwise Operators
Go provides the following bitwise operators:
&
: BitwiseAND
|
: BitwiseOR
^
: BitwiseXOR
&^
: Bit clear(AND NOT)
<<
: Left shift>>
: Right shift
Bitwise operators in Go deal with bit – 0
and 1
and work only on integer variables having bit patterns of equal length. The format-string %b
is used for bit-representation. Here is a quick code example showing how to take user input and format it as a binary number in Go:
package main
import "fmt"
func main() {
var i int
fmt.Printf("Enter number:")
fmt.Scanf("%d", &i)
fmt.Printf("Number %d in binary is %b", i, i)
}
Running this code in your integrated development environment (IDE) gives us the following output:
Enter number:34
Number 34 in binary is 100010
Here, we have input a number into an integer variable through fmt.Scanf
and use the format-string %d
to print its binary form.
Use of Bit-Level Operations in Go
Below are some use cases for when a developer might use bit-level operations in Go:
- Since bitwise operators work on bit fields, they are particularly efficient in presenting something with
yes
andno
ortrue
orfalse
properties. For example, suppose a programmer wants to give or revoke permission to a file (read, write, execute). In that case, we can use only three bits instead of storing the bytes of information for the permission, such as101 = (read, execute only)
or100 (read-only)
. This saves a lot of space. - In a network transmission or communication over ports/sockets that involve parity and checksums, which depend heavily on bit operation
- All encryption and compression algorithms work on a bit level and heavily use bitwise operators
- Working with images or in graphics programming, bit-level operations help a lot, particularly the
XOR
operator, which has many interesting uses in graphics and image processing - Creating logic gates, circuit development, device drivers, finite state machines, and mathematics all have numerous uses for bitwise operators
The & (AND) Operator in Go
The &
operator in Go performs AND
operations between two integer numbers provided as an operand. The bitwise AND
operation has the following characteristics:
Note that the result is one
only when both x
and y
have value; otherwise, it results in a zero
value. The AND
operation can be used to clear — or set to 0
— certain bit positions in a number. This idea can be used in numerous creative ways. For example, if a programmer wants to find a number ODD
or EVEN
, they may use the &
operator in the following way:
x := 125
if (x & 0x1) > 0 {
fmt.Println("ODD")
} else {
fmt.Println("EVEN")
}
This trick works because every ODD
number has one
as the least significant bit (LSB), and the AND
operation will clear all the bits except the LSB. As such, the result of the if-condition
will be accurate
if the value ANDed
with 0x1
is greater than 0
, which means the number is ODD
and false
otherwise.
The | (OR) Operator in Go
The |
operator in Go performs OR
operations between two integer numbers provided as an operand. The bitwise OR
operation has the following characteristics:
Note that the result is 1 when at least one input is 1
and 0
otherwise. This property can be used to set certain bits, unlike AND
, which can be used to clear certain bits. Suppose we want to put the LSB of a decimal 10
(in binary 1010
). After setting the LSB, the result should be 11
(in binary 1011
). Here is the code to perform this task:
var set_bit uint32 = 0x1
var value uint32 = 0xA
fmt.Printf("%b", value|set_bit)
So if the & (AND) operation can be used to clear bits, | (OR) can be used to set bits.
The ^ (XOR) Operator in Go
The ^
operator in Go performs OR
operations between two integer numbers provided as an operand. The bitwise OR
operation has the following characteristics:
In this case, the output is 1
only when both the input values are different. If both input values are the same, it would result in 0
when XORed
. The XOR
operator has many interesting uses in computing. It is mainly used to toggle values, such as changing value 0
to 1
and 1
to 0
in a sequence of bits. A common trick with XOR
is swapping two variables' values without using a third/another variable. Here is a code example showing how to execute this idea in Go:
x := 5
y := 6
fmt.Printf("nBefore swap: x=%d,y=%d", x, y)
x = x ^ y
y = x ^ y
x = x ^ y
fmt.Printf("nAfter swap x=%d,y=%d", x, y)
The above Golang code exchanges (or swaps) the value stored in x
to y
and y
to x
using the XOR
operator.
The &^ (AND NOT) Operator in Go
The &^ (AND NOT)
operator in Go is interesting because the actual operator is ^,
and the &^
is used to separate it from the XOR
operator. The reason is that unlike C/C++, which has a dedicated unary NOT
operator represented by the exclamation sign (!
), Go does not have a bitwise NOT
operator (not to be confused with the !
Logical not operator). Therefore, to negate anything, programmers can use the same ^ (XOR)
operator acting as a bitwise NOT
. The bitwise NOT
produces one’s complement of a number. So, a given bit x
and ^x
would complement one another. Here is a simple code example showing how to use the &^ (AND NOT)
operator in Go:
var x uint8 = 129
fmt.Printf("n x=%b,^x=%b", x, ^x)
The << and >> Operators in Go
The <<
(left-shift) and >>
(right-shift) operators in Go shift the number of bit positions to the left by inserting 0
as the LSB and to the right by inserting 0
to the MSB, respectively. For example, a given integer x
can be shifted left by n
bits or shifted right by n
bits as follows:
x << n, shifts x to the left by n bits x >> n, shift x to the right by n bits
Among many of its interesting uses in programming, if programmers shift a number by 1
bit, it gives a result of the value multiplied by 2
. Similarly, if we right-shift a number by 1
bit, we get a quotient of the value divided by 2
. Here is a quick code example illustrating the idea:
var x uint8 = 10
fmt.Printf("n%d x 2 = %d", x, x<<1) fmt.Printf("n%d / 2 = %d", x, x>>1)
Final Thoughts on Bitwise Operators in Go
Developers often encounter confusion when distinguishing between bitwise and logical operators, as both perform similar operations. To clarify, bitwise operators always return numeric bit values, whereas logical operators produce only boolean values (true
or false
), which are non-numeric. This distinction is crucial for understanding their behavior. Bitwise operations can be particularly useful for optimizing complex logic, transforming lengthy conditions into more efficient expressions. In Go, working with bitwise operators provides a low-level, performance-oriented approach that can be both powerful and rewarding.
Opinions expressed by DZone contributors are their own.
Comments