[C 語言] Bitwise operation note

前言

bitwise operation 對於 ic 韌體設計,以及 embedded system 的韌體設計,都是一個非常重要的存在

為了節省空間,通常一個晶片的數值空間中,每一個 bit 都會代表一個功能,此時如果我們要設定該功能的時候,就不能單單直接 assign 一個數值,這樣可能會更動到其他的 bit 使得其他功能被你更動

因此才衍伸出「bitwise operation」這種程式方式,學習此技能後,對於 embedded linux / bare-metal / MCU / SoC register 的設定方式都會更容易了解

在此收集了一些有趣的問題,並且練習一下

取一個 8bit 數值的最高位元位置

使用二分法

1
2
3
4
5
6
7
8
9
10
int get_highest_bit_position(unsigned char x)
{
int n = 7;
if (x == 0) return -1; /* position not found */
if ((x >> 4) == 0) { n = n-4; x=x << 4}
if ((x >> 6) == 0) { n = n-2; x=x << 2}
if ((x >> 7) == 0) { n = n-1;}

return n;
}

取一個 8bit 數值的最低位元位置

最低位元,很有趣,使用 2’s compliment 就可以完成,比如說

1
2
3
4
5
6
7
0x34

0011 0100
2's 1100 1011 + 1
& 1100 1100
---------------------
0000 0100 ---------> result

這時候我們再用剛剛的找最高位元找出答案就可以了

1
2
3
4
5
int get_lower_bit_position(unsigned char x)
{
x = x & (-x);
return get_highest_bit_position(x);
}

取出一個 unsigned int 數值中含有 1 個數的總和

我們做個比方好了

1
2
3
4
5
6
7
8
0x5a5a
0101 1010 0101 1010
- 1
------------------------------
0101 1010 0101 1001
& 0101 1010 0101 1010
------------------------------
0101 1010 0101 1000

這樣就會消除最低 bit
之後我們繼續做,就可以消除倒數第二的 bit,以此類推

1
2
3
4
5
6
7
8
9
10
int numbers_of_1_in_int(unsigned int x)
{
int count = 0;
while (x!=0)
{
x = x & (x-1);
count++;
}
return count;
}

如何偵測這個數值是 2 的 n 次方?

簡單說 2 的 n 次方,可以認為是「在這個數值中,bit 中含 1 的個數為 1」

因此可以寫成

1
2
3
4
bool is_nth_power_of_two(unsigned int x)
{
return (1 == numbers_of_1_in_int(x)) ? true : false;
}

set bit x

這個就是基本題了,使用 or gate 就可以了

1
2
3
4
5
unsigned int set_bit(unsigned int x, int bitnum)
{
x = (x | 1 << bitnum);
return x;
}

當然簡化寫法就是 x |= 1<<bitnum

clear bit x

這個也是基本題

做個比方

0x43 清掉 第 6 個 bit

1
2
3
4
5
0x43
0010 0011
& 1101 1111 =====> ~(1 << bitnum)
-------------------
0000 0011

所以答案就是

1
2
3
4
5
unsigned int clear_bit(unsigned int x, int bitnum)
{
x = x & ~(1<<bitnum);
return x;
}

也可以寫成 x &= ~(1<<bitnum)