一、進制基礎知識
1、通常,1字節(Byte)包含8位(bit)。C語言用字節表示儲存系統字符集所需的大小。
2、對於一個1字節8位的二進制數,最右邊(第0位)是最低階位,最左邊(第1位)是最高階位,第幾位表示2的指數大小。
3、1字節(8位)可存儲256個值,unsigned char用1字節表示的范圍是0-255,signed char用1字節表示的范圍是(-128)-(+127)。
4、每個8進制位對應3個二進制位,每個16進制位對應4個二進制位。
5、補碼反碼等與有符號整數有關的部分省略。
二、C操控位工具(2)——按位運算符
注意:按位運算符操作的位不會改變其它位。
邏輯運算符的優先級低於算數運算符。
1、按位邏輯運算符 ~ & | ^
1.1、二進制按位取反運算符~
簡單來說就是每一位都取相反數,1變成0,0變成1,規則如下:
(~1) = 0,(~0) = 1
示例如下:
~(10011010) //結果為01100101,每一位都取相反數
1.2、二進制按位與運算符&
簡單來說全為1則結果為1,不全為1或者全不為1則結果為0,規則如下:
1 & 1 = 1,1 & 0 = 0, 0 & 0 = 0,結果操作位在運算符左右位置無關
示例如下:
(10000011) & (00111101) //結果為00000001,只有最后一位全為1
1.3、二進制按位或運算符|
簡單來說就是有1(全為1或者不全為1)則結果為1,全不為1(全為0)則結果為0,規則如下:
1 | 1 = 1,1 | 0 = 1, 0 | 0 = 0,結果操作位在運算符左右位置無關
示例如下:
(10000010) | (01111100) //結果為11111110,只有最后一位全為0
1.4、二進制按位異或運算符^
簡單來說就是操作位數值相同(全為0或者全為1)為0,相反(一個0一個1)為1,規則如下:
1 ^ 1 = 0,1 ^ 0 = 1, 0 ^ 0 = 0,結果操作位在運算符左右位置無關
示例如下:
(10000010) ^ (01111110) //結果為11111100,最第為全為0,第二位全為1,其它位均相反
1.5、應用
根據按位邏輯運算符可進行 打開位(設置位)、關閉位(清空位)、切換位、檢查位的值等操作。
2、移位運算符
注意:移位運算符向左或者向右移位,被移出的位直接丟棄,移進的位補0。
2.1、左移運算符<<
示例如下:
(10001010) << 2 //結果為00101000
2.2、右移運算符>>
示例如下:
(10001010) >> 2 //結果為00100010
2.3、應用
針對2的冪可快速進行有效的乘法和除法,類似十進制中移動小數點來乘以或除以10,如下所示:
number << n //表示number乘以2的n次冪 number >> n //若number非負,則用number除以2的n次冪
三、C操控位工具(2)——位字段
1、位字段簡介
位字段是一個signed int或者unsigned int類型變量中的一組相鄰的位,需通過一個結構體聲明來建立,該結構為每個字段提供標簽,並確定該字段的寬度。如下所示:
/* 定義一個包含4個成員變量的結構體prnt,每個成員的位寬為1 */ struct{ unsigned int autfd : 1; unsigned int bldfc : 1; unsigned int undln : 1; unsigned int itals : 1; }prnt; /* 為結構體成員賦值 */ prnt.itals = 0; prnt.undln = 1; /* 定義一個包含2個成員變量的結構體prcode,成員變量位寬不一 */ struct{ unsigned int code1 : 2; unsigned int code2 : 8; }prcode; /* 為結構體成員賦值 */ prcode.code1 = 3; /**< code1最大可賦值3 */ prcode.code1 = 100; /**< 賦值范圍在0-255中均可 */
變量prnt會prcode被儲存在int大小的內存單元中。
2、聲明的總位數超過范圍的解決方法
如果聲明的總位數超過一個unsigned int類型的大小,則會用到下一個unsigned int類型的存儲位置。一個字段不允許跨越兩個unsigned int之間的邊界。編譯器會自動移動跨界的字段,保持
unsigned int的邊界對齊。一旦發生這種情況,第一個unsigned int 中會保留一個未命名的"洞",可用此未命名的洞來填充超過的位數。如下所示:
struct{ unsigned int field1 : 1; unsigned int : 2; /**< 填補field1的"洞" */ unsigned int field2 : 1; unsigned int : 0; /**< 填補field2的"洞" */ unsigned int field3 : 1; /**< 填補field3的"洞"並未給出 */ }stuff;
位字段在unsigned int中存儲的位置根據機器而定,有些從右往左順序存儲,有些則從左往右,由於這些原因位字段通常都不容易移植。