208 lines
6.5 KiB
Markdown
208 lines
6.5 KiB
Markdown
---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](http://en.wikipedia.org/wiki/C_data_types#Basic_types) 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`.
|
|
|
|
```c
|
|
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`:
|
|
|
|
```c
|
|
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`:
|
|
|
|
```c
|
|
storage ^= 1 << n;
|
|
```
|
|
|
|
```
|
|
01000010 01001010
|
|
XOR XOR
|
|
00001000 00001000
|
|
== ==
|
|
01001010 01000010
|
|
```
|
|
|
|
## Memeriksa bit n
|
|
|
|
Memeriksa bit adalah ANDing nilai `2^n` dengan penyimpanan bit:
|
|
|
|
```c
|
|
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--- |