Operator bitwise bekerja pada susunan bit di dalam bilangan integer, bukan pada nilai desimalnya. Inilah alat ketika kita mengelola sekumpulan penanda on/off dalam satu angka, menghitung checksum, berkomunikasi dengan perangkat keras, atau mengatur permission ala Unix (rwx). Ada enam operatornya: &, |, ^, ~, <<, dan >>. Untuk melihat hasilnya dengan jelas, program pada Chapter ini mencetak bilangan dalam bentuk biner memakai std::format("{:b}", ...) — alat pemformatan teks dari header <format> yang dibahas tuntas pada Section Standard Library.
Enam Operator Bitwise #
Lima operator pertama memasangkan bit pada posisi yang sama dari dua operand (untuk ~, satu operand). Berikut aturan per pasangan bit, dengan bit 1 berarti menyala:
| Operator | Nama | Aturan per bit | Contoh 0b1100 op 0b1010 |
|---|---|---|---|
& | AND | 1 bila keduanya 1 | 0b1000 |
| | OR | 1 bila salah satunya 1 | 0b1110 |
^ | XOR | 1 bila keduanya berbeda | 0b0110 |
~ | NOT (unary) | membalik semua bit | seluruh 32 bit terbalik |
<< | geser kiri | bit bergeser ke kiri | diuji di bawah |
>> | geser kanan | bit bergeser ke kanan | diuji di bawah |
Litera 0b... adalah cara menulis bilangan biner langsung di kode, misalnya 0b1100 yang berarti 12 desimal. Bentuk ini juga sudah kita lihat pada Chapter Integer di Section Variabel dan Tipe Data.
#include <format>
#include <iostream>
int main() {
std::cout << std::boolalpha;
// std::format("{:b}", x) mencetak bilangan dalam bentuk biner;
// alat pemformatan ini dibahas tuntas pada Section Standard Library.
unsigned int a = 0b1100; // 12 dalam desimal
unsigned int b = 0b1010; // 10 dalam desimal
std::cout << "a = 0b" << std::format("{:b}", a) << " (" << a << ")\n";
std::cout << "b = 0b" << std::format("{:b}", b) << " (" << b << ")\n\n";
// Bitwise: bit di posisi yang sama dipasangkan
std::cout << "a & b = 0b" << std::format("{:b}", a & b) << " -> " << (a & b) << "\n";
std::cout << "a | b = 0b" << std::format("{:b}", a | b) << " -> " << (a | b) << "\n";
std::cout << "a ^ b = 0b" << std::format("{:b}", a ^ b) << " -> " << (a ^ b) << "\n";
std::cout << "~a = 0b" << std::format("{:b}", ~a) << " -> " << ~a << "\n\n";
// Shift: menggeser bit = kali/bagi pangkat dua
unsigned int n = 6;
std::cout << "6 << 2 = " << (n << 2) << " (6 * 4)\n";
std::cout << "24 >> 2 = " << ((n << 2) >> 2) << " (24 / 4)\n\n";
// Pola set / check / clear bit dengan mask
unsigned int flag = 0b0000;
unsigned int MASK = 0b0100; // bit ke-2
flag = flag | MASK; // set: nyalakan bit ke-2
std::cout << "set bit ke-2 : 0b" << std::format("{:b}", flag) << "\n";
std::cout << "bit ke-2 aktif? : " << ((flag & MASK) != 0) << "\n";
flag = flag & ~MASK; // clear: matikan bit ke-2
std::cout << "clear bit ke-2 : 0b" << std::format("{:b}", flag) << "\n";
std::cout << "bit ke-2 aktif? : " << ((flag & MASK) != 0) << "\n";
return 0;
}Output yang Dihasilkan:
a = 0b1100 (12)
b = 0b1010 (10)
a & b = 0b1000 -> 8
a | b = 0b1110 -> 14
a ^ b = 0b110 -> 6
~a = 0b11111111111111111111111111110011 -> 4294967283
6 << 2 = 24 (6 * 4)
24 >> 2 = 6 (24 / 4)
set bit ke-2 : 0b100
bit ke-2 aktif? : true
clear bit ke-2 : 0b0
bit ke-2 aktif? : falseMari kita bedah:
- Baris 10-11:
adiisi0b1100danbdiisi0b1010; keduanya dicetak ulang dalam biner beserta nilai desimalnya agar mudah dicek. - Baris 18-20 (
&,|,^): bandingkan tiap kolom bit. AND menyala hanya di posisi yang sama-sama menyala (1000), OR menyala bila salah satu menyala (1110), dan XOR menyala bila keduanya berbeda (0110). - Baris 21 (
~a): unary NOT membalik seluruh 32 bit milikunsigned int, sehingga muncul 28 angka1di depan; hasil desimalnya4294967283. Ini memperlihatkan bahwa~bekerja pada semua bit, bukan hanya empat bit terakhir. - Baris 25-26 (shift):
6 << 2menggeser bit ke kiri dua langkah sehingga bernilai24, lalu24 >> 2kembali ke6. - Baris 30-38 (mask): variabel
MASKmenandai bit ke-2. Pola set, check, dan clear bit dijelaskan pada bagian akhir Chapter.
Geser Bit: Kali dan Bagi Pangkat Dua #
Menggeser bit kiri n langkah sama hasilnya dengan mengalikan 2^n, dan menggeser kanan n langkah sama dengan membagi 2^n (bagian pecahan dibuang, seperti pembagian integer). Karena itu compiler sering menerjemahkan perkalian/divisi dengan pangkat dua menjadi satu instruksi shift — operasi yang sangat murah di CPU. Pola ini hanya berlaku untuk integer; untuk tipe floating-point tidak ada padanan shift-nya.
Pola Set, Check, dan Clear Bit #
Pola paling sering dipakai bitwise adalah mengelola flag: beberapa penanda on/off yang dikemas dalam satu integer. Setiap bit berdiri untuk satu penanda, dan MASK adalah konstanta yang menandai posisi bit yang sedang digarap. Dari output program di atas, tiga langkahnya terbaca jelas:
- Set bit:
flag | MASKmenyalakan bit ke-2 tanpa menyentuh bit lain, hasilnya0b100. - Check bit:
(flag & MASK) != 0menghasilkantruehanya bila bit ke-2 menyala. Hasil&dengan mask bisa dipakai langsung sebagai kondisi. - Clear bit:
flag & ~MASKmembalik mask (bit ke-2 jadi0, sisanya1) sehingga hanya bit ke-2 yang dipadamkan; hasilnya kembali0b0.
Dengan tiga langkah ini kita bisa memakai satu unsigned int sebagai ladang penanda alih-alih delapan bool terpisah — teknik yang lazim di driver, jaringan, dan game. Untuk set bit pada posisi berapapun secara dinamis, kombinasi 1u << posisi membuat mask-nya on the fly.
Operator bitwise memilih nilai berdasarkan bit. Chapter berikutnya membahas operator yang juga memilih antara dua nilai, tetapi berdasarkan kondisi bool — operator ternary kondisi ? a : b.