Operator bitwise adalah alat untuk bekerja langsung di level bit. Setiap nilai di C disimpan sebagai deretan bit di memori, dan operator bitwise memungkinkan kita memanipulasi bit-bit tersebut satu per satu. Pada Chapter ini kita akan menelaah enam operator bitwise di C: & (AND), | (OR), ^ (XOR), ~ (NOT), << (geser kiri), dan >> (geser kanan). Operator-operator ini adalah pondasi dari pemrograman low-level seperti penulisan device driver, manipulasi hardware register, kompresi data, kriptografi, hingga optimasi performa pada embedded systems. Kita juga akan menelaah beberapa idiom klasik: pemeriksaan ganjil/genap dengan & 1, manipulasi bitmask dengan shift, hingga trik swap variabel tanpa variabel sementara menggunakan XOR.
Enam Operator Bitwise #
| Operator | Nama | Contoh a=0xCA, b=0xB5 | Hasil |
|---|---|---|---|
& | AND bitwise | a & b | 0x80 |
| | OR bitwise | a | b | 0xFF |
^ | XOR bitwise | a ^ b | 0x7F |
~ | NOT bitwise (unary) | ~a | bit dibalik |
<< | Shift kiri | a << 2 | 0x328 |
>> | Shift kanan | a >> 2 | 0x32 |
Operator bitwise bekerja pada representasi biner nilai integer, bit demi bit. Hasil setiap operator mengikuti tabel kebenaran untuk bit tunggal: 1 & 1 = 1, 1 | 0 = 1, 1 ^ 1 = 0, ~1 = 0, dan seterusnya.
#include <stdio.h>
void cetak_biner(unsigned int nilai, int lebar) {
for (int i = lebar - 1; i >= 0; i--) {
putchar((nilai >> i) & 1 ? '1' : '0');
}
}
int main(void) {
unsigned int a = 0b11001010; /* 202 */
unsigned int b = 0b10110101; /* 181 */
printf("a = "); cetak_biner(a, 8); printf(" (0x%X)\n", a);
printf("b = "); cetak_biner(b, 8); printf(" (0x%X)\n", b);
printf("a & b = "); cetak_biner(a & b, 8); printf(" (0x%X)\n", a & b);
printf("a | b = "); cetak_biner(a | b, 8); printf(" (0x%X)\n", a | b);
printf("a ^ b = "); cetak_biner(a ^ b, 8); printf(" (0x%X)\n", a ^ b);
printf("~a = "); cetak_biner(~a, 8); printf(" (0x%X)\n", ~a);
printf("a << 2 = "); cetak_biner(a << 2, 8); printf(" (0x%X)\n", a << 2);
printf("a >> 2 = "); cetak_biner(a >> 2, 8); printf(" (0x%X)\n", a >> 2);
return 0;
}Output yang Dihasilkan:
a = 11001010 (0xCA)
b = 10110101 (0xB5)
a & b = 10000000 (0x80)
a | b = 11111111 (0xFF)
a ^ b = 01111111 (0x7F)
~a = 00110101 (0xFFFFFF35)
a << 2 = 00101000 (0x328)
a >> 2 = 00110010 (0x32)Mari kita telaah baris-baris kode di atas:
- Baris 4-8 (
cetak_biner): fungsi cetak biner 8 bit dengan loop dari bit ke-7 ke bit ke-0; ekspresi(nilai >> i) & 1menggeser nilai sehingga bit ke-i menjadi bit paling rendah, lalu di-AND dengan1untuk mengisolasi bit tunggal tersebut. - Baris ke-17 (
a & b): AND bitwise—hanya bit yang1di kedua operand yang tetap1; hasil0b10000000. - Baris ke-19 (
a ^ b): XOR bitwise—bit1jika dan hanya jika kedua operand berbeda; hasil0b01111111. - Baris ke-20 (
~a): NOT unary—membalik setiap bit; namun karenaabertipeunsigned int(32 bit), hasilnya dilengkapi bit1di 24 bit atas sehingga nilai heksadesimalnya0xFFFFFF35. Fungsicetak_binerhanya menampilkan 8 bit paling rendah. - Baris ke-21 (
a << 2): shift kiri 2 posisi—setara dengan perkaliana * 4; bit-bit baru yang masuk dari kanan selalu0.
Idiom Manipulasi Bitmask #
Pola paling umum di pemrograman low-level adalah memeriksa, menyetel, menghapus, dan men-toggle bit ke-n pada sebuah register atau flag. Empat operasi ini memiliki idiom baku yang berpusat pada ekspresi 1U << n yang menghasilkan bitmask dengan hanya satu bit bernilai 1 di posisi ke-n.
#include <stdio.h>
/* Cek apakah bit ke-n diset */
int cek_bit(unsigned int nilai, int n) {
return (nilai >> n) & 1U;
}
/* Set bit ke-n */
unsigned int set_bit(unsigned int nilai, int n) {
return nilai | (1U << n);
}
/* Clear bit ke-n */
unsigned int clear_bit(unsigned int nilai, int n) {
return nilai & ~(1U << n);
}
/* Toggle bit ke-n */
unsigned int toggle_bit(unsigned int nilai, int n) {
return nilai ^ (1U << n);
}
int main(void) {
unsigned int data = 0b00001010; /* 10 */
printf("data awal : 0b00001010 = %u\n", data);
printf("bit ke-1 diset? : %d\n", cek_bit(data, 1));
printf("bit ke-3 diset? : %d\n", cek_bit(data, 3));
unsigned int hasil = set_bit(data, 0);
printf("set_bit(0) : %u\n", hasil);
hasil = clear_bit(data, 3);
printf("clear_bit(3) : %u\n", hasil);
hasil = toggle_bit(data, 1);
printf("toggle_bit(1) : %u\n", hasil);
return 0;
}Output yang Dihasilkan:
data awal : 0b00001010 = 10
bit ke-1 diset? : 1
bit ke-3 diset? : 1
set_bit(0) : 11
clear_bit(3) : 2
toggle_bit(1) : 8Pada baris ke-28, cek_bit(data, 1) menggeser data ke kanan satu posisi sehingga bit ke-1 menjadi bit ke-0, lalu di-AND dengan 1U. Hasilnya 1 yang berarti bit ke-1 memang diset. Pada baris ke-31, set_bit(data, 0) meng-OR data dengan 0b00000001 untuk memastikan bit ke-0 menjadi 1 tanpa mengubah bit lain; 10 | 1 = 11.
Idiom Lain: Ganjil/Genap, Popcount, dan Swap dengan XOR #
Operator bitwise memungkinkan banyak trik ringkas. Pemeriksaan ganjil/genap dapat dilakukan dengan n & 1 alih-alih n % 2. Operasi popcount (menghitung jumlah bit bernilai 1) dapat dilakukan dengan loop shift. Bahkan swap dua variabel dapat dilakukan tanpa variabel sementara menggunakan tiga operasi XOR berturut-turut.
#include <stdio.h>
/* Cek ganjil/genap dengan & 1 */
const char *ganjil_genap(int n) {
return (n & 1) ? "ganjil" : "genap";
}
/* Hitung bit '1' (popcount) */
int hitung_bit(unsigned int n) {
int count = 0;
while (n) {
count += n & 1;
n >>= 1;
}
return count;
}
int main(void) {
int angka[] = {7, 10, 15, 16, 255};
int jumlah = sizeof(angka) / sizeof(angka[0]);
for (int i = 0; i < jumlah; i++) {
printf("%3d adalah %s, jumlah bit 1 = %d\n",
angka[i],
ganjil_genap(angka[i]),
hitung_bit((unsigned int)angka[i]));
}
/* Swap tanpa variabel sementara menggunakan XOR */
int a = 25, b = 17;
printf("\nSebelum swap: a=%d, b=%d\n", a, b);
a ^= b;
b ^= a;
a ^= b;
printf("Setelah swap: a=%d, b=%d\n", a, b);
return 0;
}Output yang Dihasilkan:
7 adalah ganjil, jumlah bit 1 = 3
10 adalah genap, jumlah bit 1 = 2
15 adalah ganjil, jumlah bit 1 = 4
16 adalah genap, jumlah bit 1 = 1
255 adalah ganjil, jumlah bit 1 = 8
Sebelum swap: a=25, b=17
Setelah swap: a=17, b=25Pada baris ke-25, n & 1 mengisolasi bit ke-0; jika 1, maka n ganjil. Pada baris ke-41, swap XOR bekerja karena a ^ a = 0 dan a ^ 0 = a. Setelah a ^= b, variabel a menyimpan gabungan XOR keduanya; operasi b ^= a mengembalikan nilai asli a ke b; operasi a ^= b mengembalikan nilai asli b ke a.
Operator bitwise membuka pintu ke pemrograman level rendah. Pada Chapter berikutnya, kita akan melihat operator conditional ? : yang memungkinkan percabangan ringkas dalam satu ekspresi.