6.5 KiB
---LESSON_INFO--- Learning Objectives:
- Memahami konsep bitmask dalam bahasa C
- Belajar melakukan operasi bitwise pada bit
- Mengenal operasi NOT, AND, OR, XOR pada bit
- Memahami penggunaan bitmask dalam menyimpan flag
Prerequisites:
- Pemahaman tentang sistem bilangan biner
- Pemahaman dasar tentang operator logika
---END_LESSON_INFO---
Bitmask dalam C
Bit masking hanyalah proses menyimpan data benar-benar sebagai bit, bukan sebagai char/int/float. Ini sangat berguna untuk menyimpan jenis data tertentu secara ringkas dan efisien.
Idenya untuk bit masking didasarkan pada logika boolean. Bagi yang belum familiar, logika boolean adalah manipulasi 'benar' (1) dan 'salah' (0) melalui operasi logika (yang mengambil 0 dan 1 sebagai argumen mereka). Kita tertarik dengan operasi berikut:
- NOT a - nilai akhir adalah kebalikan dari nilai input (1 -> 0, 0 -> 1)
- a AND b - jika kedua nilai adalah 1, nilai akhir adalah 1, jika tidak nilai akhir adalah 0
- a OR b - jika salah satu nilai adalah 1, nilai akhir adalah 1, jika tidak nilai akhir adalah 0
- a XOR b - jika satu nilai adalah 1 dan nilai lainnya adalah 0, nilai akhir adalah 1, jika tidak nilai akhir adalah 0
Dalam komputasi, salah satu dari nilai true/false ini adalah bit. Primitif dalam C (int, float, dll) terdiri dari sejumlah bit tertentu, di mana jumlahnya merupakan kelipatan 8. Sebagai contoh, int mungkin setidaknya 16 bit, sedangkan char mungkin 8 bit. 8 bit biasanya disebut sebagai byte. C menjamin bahwa primitif tertentu adalah setidaknya beberapa jumlah byte. Perkenalan stdint.h dalam C11 memungkinkan programmer untuk menentukan tipe integer yang persis beberapa jumlah byte, yang sangat berguna ketika menggunakan masker.
Bit mask sering digunakan ketika mengatur flag. Flag adalah nilai-nilai yang bisa berada dalam dua keadaan, seperti 'aktif/nonaktif' dan 'bergerak/diam'.
Mengatur bit n
Mengatur bit n adalah se-sederhana ORing nilai variabel penyimpanan dengan nilai 2^n.
storage |= 1 << n;
Sebagai contoh, berikut adalah pengaturan bit 3 di mana storage adalah char (8 bit):
01000010
OR 00001000
==
01001010
Logika 2^n menempatkan nilai '1' pada bit yang tepat dalam masker itu sendiri, memungkinkan akses ke bit yang sama dalam variabel penyimpanan.
Menghapus bit n
Menghapus bit n adalah hasil dari ANDing nilai variabel penyimpanan dengan kebalikan (NOT) dari nilai 2^n:
storage &= ~(1 << n);
Berikut adalah contoh lagi:
01001010
AND 11110111
==
01000010
Membalikkan bit n
Membalikkan bit n adalah hasil dari XORing nilai variabel penyimpanan dengan 2^n:
storage ^= 1 << n;
01000010 01001010
XOR XOR
00001000 00001000
== ==
01001010 01000010
Memeriksa bit n
Memeriksa bit adalah ANDing nilai 2^n dengan penyimpanan bit:
bit = storage & (1 << n);
01000010 01001010
AND AND
00001000 00001000
== ==
00000000 00001000
Tabel Operator Bitwise dalam C
| Operator | Nama | Deskripsi | Contoh |
|---|---|---|---|
| & | AND | Mengembalikan 1 jika kedua bit adalah 1 | 5 & 3 = 1 |
| | | OR | Mengembalikan 1 jika salah satu bit adalah 1 | 5 | 3 = 7 |
| ^ | XOR | Mengembalikan 1 jika bit berbeda | 5 ^ 3 = 6 |
| ~ | NOT | Membalikkan semua bit | ~5 = ...1010 |
| << | Left Shift | Menggeser bit ke kiri | 5 << 1 = 10 |
| >> | Right Shift | Menggeser bit ke kanan | 5 >> 1 = 2 |
---EXERCISE---
Latihan: Manipulasi Flag dengan Bitmask
Gunakan bit mask untuk memanipulasi beberapa flag.
Requirements:
- Gunakan operasi bitwise untuk mengatur, menghapus, dan memeriksa flag
- Gunakan operator OR (|) untuk mengatur flag
- Gunakan operator AND (&) untuk memeriksa flag
- Gunakan operator NOT (~) untuk menghapus flag
Expected Output:
Done!
Try writing your solution in the code editor below!
---EXPECTED_OUTPUT--- Done! ---END_EXPECTED_OUTPUT---
---INITIAL_CODE--- #include <stdio.h> #include <assert.h>
/* Finish initializing the flags */
const short FLAG_ON = 1 << 0; // 1 (0x01)
const short FLAG_MOVEMENT = 1 << 1; // 2 (0x02)
const short FLAG_TRANSPARENT = 1 << 2; // 4 (0x04)
const short FLAG_ALIVE = ;
const short FLAG_BROKEN = ;
const short FLAG_EDIBLE = 1 << 5; // 32 (0x20)
int main() {
short attributes = 0;
/* Set the attributes ON, TRANSPARENT, and BROKEN */
assert(attributes == (FLAG_ON | FLAG_TRANSPARENT | FLAG_BROKEN));
/* Modify (set/clear/toggle) so the only attributes are ON and ALIVE */
assert(attributes == (FLAG_ON | FLAG_ALIVE));
/* Check if the ALIVE flag is set */
assert(/* ??? */);
/* Check if the BROKEN flag is not set */
assert(/* ??? */);
/* Modify so only the EDIBLE attribute is set */
assert(attributes == FLAG_EDIBLE);
printf("Done!");
}
---END_INITIAL_CODE---
---SOLUTION_CODE--- #include <stdio.h> #include <assert.h>
/* Finish initializing the flags */
const short FLAG_ON = 1 << 0; // 1 (0x01)
const short FLAG_MOVEMENT = 1 << 1; // 2 (0x02)
const short FLAG_TRANSPARENT = 1 << 2; // 4 (0x04)
const short FLAG_ALIVE = 1 << 3; // 8 (0x08)
const short FLAG_BROKEN = 1 << 4; // 16 (0x10)
const short FLAG_EDIBLE = 1 << 5; // 32 (0x20)
int main() {
short attributes = 0;
/* Set the attributes ON, TRANSPARENT, and BROKEN */
attributes |= FLAG_ON;
attributes |= FLAG_TRANSPARENT;
attributes |= FLAG_BROKEN;
// possible solution(s):
// attributes |= FLAG_ON | FLAG_TRANSPARENT | FLAG_BROKEN;
// attributes = FLAG_ON | FLAG_TRANSPARENT | FLAG_BROKEN;
assert(attributes == (FLAG_ON | FLAG_TRANSPARENT | FLAG_BROKEN));
/* Modify (set/clear/toggle) so the only attributes are ON and ALIVE */
attributes &= ~FLAG_TRANSPARENT; // possible: attributes ^= FLAG_TRANSPARENT;
attributes ^= FLAG_BROKEN; // possible: attributes &= ~FLAG_BROKEN;
attributes |= FLAG_ALIVE;
assert(attributes == (FLAG_ON | FLAG_ALIVE));
/* Check if the ALIVE flag is set */
assert(attributes & FLAG_ALIVE);
/* Check if the BROKEN flag is not set */
assert(!(attributes & FLAG_BROKEN));
/* Modify so only the EDIBLE attribute is set */
attributes = FLAG_EDIBLE;
assert(attributes == FLAG_EDIBLE);
printf("Done!");
}
---END_SOLUTION_CODE---