# Bit Manipulation
###### tags: `EMBEDDED_C`
#### a.基本:set, clear, togger, Bit mask, shift, AND, OR, XOR
#### b.應用:有幾個bit為1, Reverse Bit, Bit Swap, Endianess Swap, Little/BIG Endian, Power of Two, 加法器
#### [練習](https://hackmd.io/cxLdBocVTBGIYpapjLkJ7A?view)
- [x] set, clear, togger,
- [x] shift
- [x] AND, OR, XOR
- [ ] Bit mask,
- [x] 有幾個bit為1(Count leading Bit)
- [x] Reverse Bit,
- [ ] Bit Swap,
- [ ] Little/BIG Endian
- [x] Endianess Swap
- [x] Power of Two
- [ ] Power of Four
- [ ] 加法器
## Uncategory
#### [水果]
- 什么是大小端存储?
- c中有哪些data type,如果想用一个data type存很多种不同类型的数据应该用什么?
- 设计一个串行协议的时候用大小端的优势和劣势?(这个想多了没答出来其实答案异常简单…)
- 写一个函数,用两个长度1byte分别存MSB,LSB。一个长度2byte的变量 把这个值存起来。
- 8-bit process, but how to obtain 16 bit value
- 写一个函数去判断系统是大端还是小端
---
## Basic Bit Manipulation
### Set Bit
```c=
ans |= 1U << k;
```
```c=
#define SET_BIT(x, n) (X |= 1U << n)
```
### Clear bit
```c=
ans &= ~(1U << k);
```
```c=
#define CLEAR_BIT(x, n) (x |= ~(1U << n))
```
### Check Bit
```c=
#define CHECK_BIT(x,n) (((x) & (1 << (n))) != 0)
```
### Toggloe Bit
```c=
ans ^= 1U << k;
```
```c=
#define TOGGLE_BIT(x, n) (x |= ~(1U << n))
```
### Reverse Bit
* Basic Idea
```c=
void reverseBit (uint32_t *p) {
while (val) {
uint32_t ret = 0;
ret = *p & 1;
ret = ret << 1;
*p = *p >> 1;
}
*p = ret;
}
```
### 判斷一整數是偶數還是奇數
> 判斷最後一位是
```c=
bool odd_even (uint32_t var) {
return (var & 1);
}
```
## Power Of Two
* Solution 1
```clike=
bool powerOf2(int var) {
if (var > 0) {
if((var & var -1) == 0)
return true;
}
return false;
}
```
* Solution 2
> 比較快 因為小於等於0可以直接省略
> 注意0不是2的倍數
```clike=
bool isPowerOfTwo(int n){
if (n <= 0) return false;
return !(n & (n - 1));
}
```
* Solution3
> true的必要條件 n > 0 && (n & (n-1) == 0)
```clike=
bool isPowerOfTwo(int n){
return (n>0&& (n&(n-1))==0)?true:false;
}
```
### 設定一個絕對位址為0x67a9的整數型變數的值為0xaa55
```c=
int *ptr;
ptr = (int *)0x67a9; // 設定指標變數的值
*ptr = 0xaa55; //設定指標變數指向的值
```
---
### 首先是给一個uint32_t返回32bit中1的個數 e.g請擷取出Input中的第七個bit值?
```clike=
int rt_7_bit(uint32_t var) {
int ans = 1 & (var >> 6);
return ans;
}
```
---
### 取一個 8bit 數值的最低位元位置
最低位元,很有趣,使用 2’s compliment 就可以完成,比如說
>0x34
```
0011 0100
2's 1100 1011 + 1
& 1100 1100
---------------------
0000 0100 ---------> result
這時候我們再用剛剛的找最高位元找出答案就可以了
```
```clike=
int get_lower_bit_position(unsigned char x)
{
x = x & (-x);
return get_highest_bit_position(x);
}
```
---
### 给一個uint32_t得到32bit中的某一位置1
```clike=
int rt_nth_bit(uint32_t var, int n) {
int ans = 1 & (var >> (n-1));
return ans
}
```
---
### 給一個uint32_t 做reverse bit
```clike=
uint32_t reverse_bit(uint32_t val) {
uint32_t ret = 0;
for(int i = 0; i < 32; i++) {
ret |= (val & 1);
ret = ret << i;
val = val >> 1;
}
return val;
}
```
---
### Trigger the nth
* the 13 bit give high!
* 0001 0000 0000 0000
* 0X1000
```clike=
Signal = Signal | 0x1000
```
```clike=
Signal = Signal | (1<<13)
```
---
### Reverse Endian with 32 bit
```c=
uint32_t endian_swap(uint32_t val) {
uint32_t swap_val = 0x0;
//seperated it for 4 parts
swap_val |= (val && 0x000000FF) << 24;//Uisng the bit Mask to get
swap_val |= (val && 0x0000FF00) << 8; //Uisng the bit Mask to get
swap_val |= (val && 0x00FF0000) >> 8; //Uisng the bit Mask to get
swap_val |= (val && 0xFF000000) >> 24;//Uisng the bit Mask to get
return swap_val;
}
```
```cpp=
Please implement the big/little endian convert
uint32_t swap_uint32( uint32_t val )
{
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
int32_t swap_int32( int32_t val )
{
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF );
return (val << 16) | ((val >> 16) & 0xFFFF);
}
```
---
## Big Enidan && Little Endian
* Adress from low to high
* E.G: `0xFF00AB11`
* **Big Endian**越前面放的越重要
| Address | 0x4000 | 0x4001 |0x4002 |0x4003
| -------- | -------- | -------- | --------| --------|
| **Byte Order** | byte0 | byte 1|byte 2|byte 3
| **Value** | 0xFF | 0x00|0xAB|0x11|
* **Little Endian** ->相反
| Address | 0x4000 | 0x4001 |0x4002 |0x4003 |
| -------- | -------- | -------- | --------| --------|
| **Byte Order** | byte0 | byte 1|byte 2|byte 3
| **Value** | 0x11 | 0xAB|0x00|0xFF|
### Check Endian(Big / Little)
* Method 1 typecasting or shifting
```c=
int main(void)
{
uint32_t u32RawData;
uint8_t *pu8CheckData;
u32RawData = 0x11223344; //Assign data
pu8CheckData = (uint8_t *)&u32RawData; //Type cast
/*
* We can also shift 24 to seek the last 8bit
*/
// *pu8CheckData = u32RawData >> 24
if (*pu8CheckData == 0x44) //check the value of lower address
{
printf("little-Endian");
}
else if (*pu8CheckData == 0x11) //check the value of lower address
{
printf("big-Endian");
}
return 0;
}
```
* Method 2 Union:
```cpp=
typedef union
{
uint32_t u32RawData; // integer variable
uint8_t au8DataBuff[4]; //array of character
} RawData;
int main(void)
{
RawData uCheckEndianess;
uCheckEndianess.u32RawData = 0x11223344; //assign the value
if (uCheckEndianess.au8DataBuff[0] == 0x44) //check the array first index value
{
printf("little-endian");
}
else if (uCheckEndianess.au8DataBuff[0] == 0x11) //check the array first index value
{
printf("big-endian");
}
return 0;
}
```
* Method 3 it with C programming
```clike=
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
union Endian{
char c[64];
uint64_t i;
};
// 1 Byte = 8 bit can be expressed 0xFF.
int main(void){
union Endian Var;
Var.i = (uint64_t)0x11223344;//0x11223344; //(4 + 4 + 4 +4) = 64 bit;
printf("sizeof is %ld\n",sizeof(Var.c[0]));
printf("The adrees of %p and val is %x \n",&(Var.c[0]),Var.c[0]);
printf("The adrees of %p and val is %x \n",&(Var.c[1]),Var.c[1]);
printf("The adrees of %p and val is %x \n",&(Var.c[2]),Var.c[2]);
printf("The adrees of %p and val is %x \n",&(Var.c[3]),Var.c[3]);
if(Var.c[0] == 0x11)
printf("Big Endian\n");
else
printf("Little Endian\n");
return 0;
}
```
---
## Big/Little Endian convertion
https://developer.arm.com/documentation/dui0491/i/Compiler-specific-Features/--rev-intrinsic
https://stackoverflow.com/questions/2182002/convert-big-endian-to-little-endian-in-c-without-using-provided-func
https://stackoverflow.com/questions/33932038/fast-conversion-of-16-bit-big-endian-to-little-endian-in-arm/33932154
___
## Bit Mask
### [Q] 32-bit machine用C語言對位址 0x00005000 的第三個bit設成0,第五個bit設成1???
>To Do: 如何 & | 一個val可以直接把這些完成
```clike=
#include <stdio.h>
int main()
{
unsigned int Obj = 0U;
unsigned int Addr = 0U;
unsigned int * pAddr ;
printf("address of obj is %#08x\n", &Obj);
scanf("%x", &Addr);
pAddr = (unsigned int*)Addr;
*pAddr&=(1U<<3) , *pAddr|=~(1U<<5);
printf("Obj = %#08x\n", Obj);
return 0;
}
```
### Bit Mask
* 最右側 3 位設為 1,其餘不變。
* ...0000 0000 0111
```clike=
*val |= 0x7;
```
* 最右側 3 位設為 0,其餘不變
```clike=
*val &= ~(0x7);
```
* 最右側 3 位執行 NOT operator,其餘不變
**觀念**:
### 取一個 8bit 數值的最高位元位置
### [Q]Bit Wise 比大小 [[Reference](https://www.zhihu.com/question/44356016)]
```clike=
int compare(uint32_t a, uint32_t b){
uint32_t diff = a ^ b; //找到兩者間不一樣的bit裡面最左邊那個
if (!diff) return 0;
// 001xxxxx -> 00100000
diff |= diff >> 1;
diff |= diff >> 2;
diff |= diff >> 4;
diff |= diff >> 8;
diff |= diff >> 16;
diff ^= diff >> 1; //最後針對這個最左邊不一樣的bit看看是a擁有還是b擁有
return a & diff ? 1 : -1;
}
```
___
## SHIFT
___
## XOR
### [Q]Swap without tmp;
>SWAP two number
>利用一個特性 a ^ a = 0; b ^ 0 = b;
>因此當我們想做交換的時候, 第二行等式
>*b = *a1 ^ *b -> *b = *a ^ *b ^ *a ->
>
```c=
void swap(uint32_t *a, uint32_t *b) {
*a ^= *b;
*b ^= *a;
*a ^= *b;
}
```
---
## Leetcode: single number
https://leetcode.com/problems/single-number/
___
## Full Adder
___
## Counting Bit
### 無號整數裡位元 == 1 的個數
* Solution 1
```c=
int counting_bit(unit32_t var) {
int count = 0;
while(var > 0) {
if ((var & 1) == 1)
count++;
var = var >> 1;
}
return count;
}
```
```c=
int bitcount(unsigned int x)
{
int count, i;
for(i = 0, count = 0; i < 32; ++i)
if((1<<i) & x)
++count;
return count;
}
```
* solution 2
```c=
int bitcount(unsigned int x)
{
int count;
for(count = 0; x != 0; x &= x - 1)
++count;
return count;
}
```
___
## Reverse Bit
___
## BIT SWAP
___
## Reference
- [ ] [LeetCode 題型整理](https://darktiantian.github.io/LeetCode%E7%AE%97%E6%B3%95%E9%A2%98%E6%95%B4%E7%90%86%EF%BC%88%E4%BD%8D%E8%BF%90%E7%AE%97%E7%AF%87%EF%BC%89Bit-Manipulation/)
- [ ] [Bit Manipulation in C](https://medium.com/techie-delight/bit-manipulation-interview-questions-and-practice-problems-27c0e71412e7)
- [ ] [面試經驗談 - C 語言篇](https://goodspeedlee.blogspot.com/2017/09/c.html)
- [ ] [[C 語言] Bitwise operation note by Timmy](http://j890111tw.blogspot.com/2019/10/bitwise-operation.html)
- [ ] [bitwise operation 面試考題 by暴肝工程司](http://j890111tw.blogspot.com/2019/10/bitwise-operation.html)