🎓 A1Learner
🔍

Rust Bitwise Operators

Bitwise operators are operators that work on the bits of a number. A number is stored as bits, a row of 1s and 0s.

AND keeps the bits both numbers have

Line the bits up. A position stays 1 only when both numbers have 1 there:

let a = 0b1100;
let b = 0b1010;
println!("{:04b}", a & b);

OR keeps any bit either number has

let a = 0b1100;
let b = 0b1010;
println!("{:04b}", a | b);

XOR keeps the bits that differ

A position becomes 1 when the two bits are different, and 0 when they match:

let a = 0b1100;
let b = 0b1010;
println!("{:04b}", a ^ b);

NOT flips every bit

let x: u8 = 0b0000_1111;
println!("{} {:08b}", !x, !x);

Shifts move the bits

One step left doubles the number. One step right halves it, dropping the fraction:

println!("{} {:04b}", 0b0011 << 1, 0b0011 << 1);
println!("{}", 0b0110 >> 1);

Set, clear and toggle bits

|= sets a bit, &= with ! clears one, and ^= flips one. These three moves are the whole toolkit:

let mut flags = 0b0000u8;
flags |= 0b0010;
flags |= 0b0100;
flags &= !0b0010;
flags ^= 0b1000;
println!("{:08b}", flags);

Example

fn main() {
    let read = 0b001;
    let write = 0b010;
    let run = 0b100;

    let mut perms = read | write;
    println!("can read = {}", (perms & read) != 0);
    println!("can run = {}", (perms & run) != 0);

    perms |= run;
    perms &= !write;
    println!("perms = {:03b}", perms);
    println!("can write = {}", (perms & write) != 0);
}

Key points

  • ! flips every bit, including the sign bit: on a signed number, !3 is -4
  • Shifting a signed number right fills the empty spaces with its sign bit.
  • So -8 >> 1 is -4.
  • On an unsigned number the spaces fill with zeros
  • A shift that is too wide is caught by Rust.
  • Too wide means 8 or more places for a u8.
  • It panics in a debug build
  • Signed numbers are stored in two's complement: to negate, flip every bit and add 1.
  • That is why -1 has the all-ones pattern.
  • In bits, -1 is 0b1111_1111.
  • Read as an unsigned u8, it is 255
  • Bitwise operators can pack several yes-or-no facts into one number.

In this example, three facts — can read, can write, can run — are packed into one number, one bit each. perms starts as read | write, the bits 011. Testing one bit is a small AND: (perms & read) != 0 asks whether the read bit survived. perms |= run switches the run bit on, and perms &= !write switches the write bit off while leaving the others alone. The last lines print the packed number as 101 and confirm the write bit is gone. This packing is exactly what the Bit Flags lesson builds on later.

Note

Rust has no >>> operator.

That sign belongs to Java and JavaScript.

Rust's >> already does the right thing for the number's own type.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

What is 0b1010 & 0b1100, in bits?