資料的表示
進位制
對於整數的表示形式有:十進位制、二進位制、八進位制、十六進位制。例如:char a= 17, b = 0B00010001, c = 021, d = 0X11; 其實 a, b, c ,d 是都相等的。寫個demo驗證一下
#include <stdio.h>
int main(int argc, char *argv[])
{
/*
* 二進位制字首: 0B 或 0b
* 八進位制字首: 0 (數字0,不是字母o)
* 十六進位制字首:0x 或 0X
*/
char a= 17, b = 0B00010001, c = 021, d = 0X11;
printf("a: %d\n", a);
printf("b: %d\n", b);
printf("c: %d\n", c);
printf("d: %d\n", d);
return 0;
}
結果:
其中 char 是一個較小的整型而已,無符號取值範圍:0~255
,有符號取值範圍:-127~127
。或許你可能會問:為什麼要叫字元型? 因為它主要用用來儲存字元的。這個時候你又會有疑問:char 的取值範圍是 -127~127
,儲存又是字元,那麼字元就是是整數? 沒錯,字元就是以整數形式儲存的,字元 'A' ~ 字元 'Z' 對應的整數是 65 ~ 90。字元 'a' ~ 字元 'z' 對應的整數是 97 ~ 122。其他對應的字元可以查 ASCII碼對照表
注意:不管是什麼進製表示,最終在計算機中都是以二進位制取運算和儲存,因為計算機就是處理01011010這樣二進位制資料,什麼十進位制、八進位制、十六進位制僅為了方便開發人員閱讀而已
補碼
對於char 用二進位制表示 0 ~ 127,即 0000 0000 ~ 0111 1111。那麼用二進位制表示 -127 ~ -1 怎麼處理?換一句話說:負數怎麼用二進位制表示? 口訣:負數的原碼取反,再加1
-127 的在計算機的表示形式:補碼,其計算過程如下:
-127的原碼:1111 1111 (左邊第一位是符號位)
-127的反碼:1000 0000 (符號位不變,其他位取反)
-127的補碼:1000 0001 (反碼的基礎上加1)
注意:整數的反碼、補碼都與原碼相同
那麼為什麼整數要用到補碼呢?
-
可以解決了負數的二進位制表示
-
消除0 和 -0的歧義,總不能一個0有兩種表示形式吧
不能char有 0000 0000 和 1000 0000 表示 0 和 -0 -
使用補碼進行計算
在計算機中整數是如何進行計算的?
使用補碼進行計算的,例如:3-5 的計算過程,當然你可能口算就知道了,但是對於計算來說沒有那麼簡單。
對於3和-5用char型別就可以儲存了。
3的補碼: 0000 0011
-5的補碼:1111 1011
表示式:3 - 5,對於計算機來說就是加法運算,即3 + (-5),用補碼做加法運算結果是:1111 1110(補碼),轉換成十進位制過程,補碼-1,即 1111 1101,然後取反(符號位不變),即1000 0010,就是十進位制的-2
演繹推算完這個過程,覺得計算機的人類先驅真的NB!!! 馮. 諾伊曼 , 圖靈,肯.湯普森,丹尼斯.裡奇,...
位操作
位操作是針對整數的。位操作運算肯定需要位操作運算子:
- ~:按位取反
- &:按位與
- |:按位或
- ^:按位異或
看到上面這些關鍵詞,這不是數位電路里面的知識嘛,這些東西怎麼跑這來了,仔細想想,計算機玩的不就是數位電路嘛。
寫個demo驗證一下位操作運算子:
#include <stdio.h>
int main(int argc, char *argv[])
{
// ~ :按位取反,即0變1,1變0
unsigned char a = 0X0f;
printf("~(0X0f): 0X%02hhx\n\n", ~a);
// &:按位與,即相同位置的值都1,結果才為1
unsigned char b = a & 0Xf0;
unsigned char c = a & 0Xff;
printf("0X0f & 0Xf0: 0X%02hhx\n", b);
printf("0X0f & 0Xff: 0X%02hhx\n\n", c);
// |:按位或,即相同位置的值有一個為1,結果就為1
unsigned char d = a | 0Xf0;
unsigned char e = a | 0Xff;
printf("0X0f | 0Xf0: 0X%02hhx\n", d);
printf("0X0f | 0Xff: 0X%02hhx\n\n", e);
// ^: 按位異或,即相同位置的值不相等,結果就為1
unsigned char f = a ^ 0Xf0;
unsigned char g = a ^ 0Xff;
printf("0X0f ^ 0Xf0: 0X%02hhx\n", f);
printf("0X0f ^ 0Xff: 0X%02hhx\n\n", g);
return 0;
}
結果:
掩碼
透過按位與&操作可以檢測某一個位的值是0還是1,例如:0B0000 0101,想檢測第1位的值,可以進行這樣的運算 --> 0B0000 0101 & 0B0000 0010, 若運算結果為非0值,則說明目標的第1位的值是1
透過按位或|操作可以設定某一個位的值是0還是1,例如:0B0000 0101,想設定第1位的值為1,可以進行這樣的運算 --> 0B0000 0101 | 0B0000 0010, 若運算結果為 0B0000 0111,則說明設定成功。
規律總結:
-
不管該位原來的值是0還是1,它跟0進行&運算,得到的結果都是0,而跟1進行&運算,將保持原來的值不變;
-
不管該位原來的值是0還是1,它跟1進行|運算,得到的結果都是1,而跟0進行|運算,將保持原來的值不變。
寫個程式碼,驗證一下:
#include <stdio.h>
int main(int argc, char *argv[])
{
// 檢測第1位的狀態
unsigned char a = 0B11110010, b = 0B11110000;
unsigned char mask = 0B00000010;
printf("0B11110010 & 0B00000010: 0X%02x\n", a & mask);
printf("0B11110000 & 0B00000010: 0X%02x\n\n", b & mask);
// 設定第1位的狀態
unsigned char d = 0B11110010, e = 0B11110011;
printf("0B11110010 | 0B00000010: 0X%02x\n", d | 0B00000010);
printf("0B11110011 | 0B00000000: 0X%02x\n\n", e | 0B00000000);
return 0;
}
結果:
目標匹配
有一個uinst32_t的數,需要驗證:第8位~第12位是00100,第21位是1。
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
bool checkBits(uint32_t num, int start, int end, uint32_t pattern)
{
uint32_t mask = ((uint32_t)1 << (end - start + 1)) - 1; // 建立掩碼
mask <<= start; // 將掩碼移到正確的位置
// 使用掩碼將不需要的位清零,然後與pattern進行比較
return ((num & mask) >> start) == pattern;
}
int target_check(uint32_t *arr, int cnt)
{
int rc = 0;
for (int i = 0; i < cnt; i++)
{
uint32_t binaryNumber = arr[i];
bool isPatternCorrect = checkBits(binaryNumber, 8, 12, 0b00100);
bool isBit21Set = checkBits(binaryNumber, 21, 21, 0b1);
if (isPatternCorrect && isBit21Set)
{
rc = 0;
printf("%d --> the value is true, (0X%08x)\n\n", i + 1, binaryNumber);
}
else
{
rc = 1;
printf("%d --> the value false , (0X%08x)\n\n", i + 1, binaryNumber);
}
}
return rc;
}
int main(int argc, char *argv[])
{
/*
* 0B00000000001000000000010000000000, 從右到左,分別是第0位,第1位,... ,第31位。
* 可以使用無符號32位的整型儲存, uint32_t num = 0B00000000001000000000010000000000;
* 32位的二進位制可以用十六進位制表示,uint32_t num = 0X00200400; 即4位二進位制可用1位十六進位制表示
*
* 要求檢測目標數值的第8位至第12位是00100,第21位是1
*/
uint32_t arr[] = {
0X00200400,
0X01200400,
0Xab300400,
0X00100400, // error
0X00200500, // error
0X00800300, // error
0B00000000001000000000010000000000,
0B00000000001000000001010100000000,
};
int cnt = sizeof(arr) / sizeof(arr[0]);
target_check(arr, cnt);
return 0;
}
結果: