https://mp.weixin.qq.com/s/Srz_K3YVLWwH7LBQeHPVZg
[TOC]
1 運(yùn)算符
~,&,|,^,<<,>>,&=,|=,^=,>>=,<<=
2 二進(jìn)制
以2為基底表示的數(shù)字為二進(jìn)制。
二進(jìn)制1111可表示為:
1*2^3 + 1*2^2 + 1*2^1 + 1*2^0
字節(jié)表示儲(chǔ)存系統(tǒng)字符集所需的大小,1字節(jié)包含8位。
二進(jìn)制無(wú)符號(hào)整數(shù)的范圍是 0 ~ 255;
有符號(hào)整數(shù)的范圍是 -127 ~ 127,因?yàn)榘宋坏牡谝晃粌?chǔ)存符號(hào)(1負(fù) 0正),只剩下7位表示數(shù)字本身。也會(huì)產(chǎn)生 +0 和 -0 兩個(gè)0.
原碼,反碼, 補(bǔ)碼
計(jì)算機(jī)中存儲(chǔ)的數(shù)據(jù)都是以二進(jìn)制碼存儲(chǔ)的,程序?qū)φ龜?shù)和負(fù)數(shù)都要進(jìn)行計(jì)算,因此增加了符號(hào)位來(lái)區(qū)分正數(shù)和負(fù)數(shù)。計(jì)算機(jī)以二進(jìn)制補(bǔ)碼來(lái)表示有符號(hào)位。
計(jì)算機(jī)中的運(yùn)算器只有加法運(yùn)算器,所以計(jì)算機(jī)只能做加法,減一個(gè)數(shù)的運(yùn)算也是通過(guò)加法實(shí)現(xiàn)相當(dāng)于加上一個(gè)這個(gè)數(shù)的相反數(shù)。
- 正數(shù):原碼=反碼=補(bǔ)碼
- 負(fù)數(shù):原碼(符號(hào)位是1)=反碼(除符號(hào)位,其他位取反)=補(bǔ)碼(反碼+1)
- 0:原碼=反碼=補(bǔ)碼=0
以8位二進(jìn)制為例:
一個(gè)二進(jìn)制和按位取反的結(jié)果相加,和必定是 11111111 即 -1, 例如十進(jìn)制2 00000010 反碼是 11111101 它兩相加(00000010 + 11111101 = 11111111)結(jié)果是 -1, 即 數(shù)+相反數(shù)=-1 得出 數(shù)+相反數(shù)+1=0 因而補(bǔ)碼是 相反數(shù)+1 的結(jié)果。
以 2 - 2 舉例: 即 2 + (-2),2在程序中的補(bǔ)碼是00000010,-2 在程序中的原碼是 10000010 反碼是 11111101 補(bǔ)碼(計(jì)算機(jī)中存儲(chǔ)的數(shù)值)是 11111110 可以得出 00000010 + 11111110 = 00000000。
以 6 - 8 舉例: 即 6 + (-8),6在程序中的補(bǔ)碼是00000110,-8 在程序中的原碼是 10001000 反碼是 11110111 補(bǔ)碼(計(jì)算機(jī)中存儲(chǔ)的數(shù)值)是 11111000 可以得出 00000110 + 11111000 = 11111110, 11111110 是 -2 的補(bǔ)碼。
以此類推,總的來(lái)說(shuō)補(bǔ)碼讓計(jì)算機(jī)可以進(jìn)行減法運(yùn)算。
3 按位邏輯運(yùn)算符
(1)二進(jìn)制反碼或按位取反: ~
-(10011010) 的結(jié)果是 (01100101), 取反就是0變1,1變0.
unsigned char a = 2; // 00000010
a = ~a;
printf("%d", a); // 11111101 即輸出 253
char a = 2; // 00000010
printf("%d", ~a);
//輸出 -3,因?yàn)閪a取反是11111101第一個(gè)是符號(hào)位,計(jì)算機(jī)判斷負(fù)數(shù),取補(bǔ)碼 10000011 即 -3
(2)按位與: &
(10010011)&(00111101) 結(jié)果是 00010001, 按位與就是兩個(gè)對(duì)比位都是1才是1,否則是0.
unsigned char a = 2; // 00000010
unsigned char b = 1; // 00000001
printf("%d", a & b); // 00000000
使用掩碼,就是按位與運(yùn)算的過(guò)程。
(3)按位或:|
(10010011)|(00111101) 結(jié)果是 10111111, 按位與就是兩個(gè)對(duì)比位只要有一位是1結(jié)果就是是1,否則是0.
(4)按位異或: ^
(10010011)^(00111101) 結(jié)果是 10101110, 按位與就是兩個(gè)對(duì)比位只要不同結(jié)果就是是1,否則是0.
4 移位運(yùn)算符
(1)左移:<<
(10010011) << 2 的結(jié)果是 01001100, 左移運(yùn)算即把每一位向左移動(dòng)指定位數(shù),移出左端的值丟失,右端空出的位置補(bǔ)0.
一個(gè)數(shù)左移2位相當(dāng)于該數(shù)乘以2的2次冪的結(jié)果。
(2)右移:>>
對(duì)無(wú)符號(hào)類型 (10010011) >> 2 的結(jié)果是 00100100;
對(duì)有符號(hào)位 (10010011) >> 2 的結(jié)果是 00100100 或 11100100, 根據(jù)系統(tǒng)的不同補(bǔ)充位可能是0也可能是符號(hào)位的副本;
右移運(yùn)算即把每一位向右移動(dòng)指定位數(shù),移出右端的值丟失,對(duì)有符號(hào)值左端空出的位置根據(jù)系統(tǒng)的不同補(bǔ)0或符號(hào)位的副本,對(duì)無(wú)符號(hào)值用0填充。
對(duì)于非負(fù)數(shù),一個(gè)數(shù)右移2位相當(dāng)于該數(shù)除以2的2次冪的結(jié)果。
編程:十進(jìn)制轉(zhuǎn)換為二進(jìn)制
#include "limits.h"
// 這個(gè)方法將整數(shù)轉(zhuǎn)換為二進(jìn)制字符串
char * itobs(int n, char * ps){
int i;
const static int size = CHAR_BIT * sizeof(int);
for (i = size - 1; i >= 0; i--, n >>= 1) {
ps[i] = (01 & n) + '0';
}
ps[size] = '\0';
return ps;
}
printf("sizeof(int) = %ld\n", sizeof(int));
char bit_str[CHAR_BIT * sizeof(int) + 1];
int number = 11;
itobs(number, bit_str);
printf("%d 的二進(jìn)制是:\n", number);
for (int i = 0; bit_str[i]; ) {
putchar(bit_str[i++]);
}
輸出:
sizeof(int) = 4
11 的二進(jìn)制是:
00000000000000000000000000001011
-11 的二進(jìn)制是:
11111111111111111111111111110101
5 位字段
struct {
unsigned int a: 1;
unsigned int b: 1;
unsigned int c: 1;
unsigned int d: 1;
} prnt;
prnt 包含 4 個(gè) 1位的字段,a,b,c,d是位字段,它們都確定了字段的寬度是1, 因?yàn)橹挥?位,所以只能賦值 0或1。
位字段是一個(gè)signedint或unsignedint類型變量中的一組相鄰的位??梢酝ㄟ^(guò)位字段來(lái)規(guī)定字段的大小。
6 對(duì)齊特性
_Alignof運(yùn)算符給出一個(gè)類型的對(duì)齊要求,在關(guān)鍵字_Alignof后面的圓括號(hào)中寫上類型名即可:
size_t f_align = _Alignof(float);
如果 f_align 的值是4,就代表float 類型對(duì)象的對(duì)其要求是4,即存儲(chǔ)float類型值需要相鄰地址的字節(jié)數(shù)是4.
使用_Alignas說(shuō)明符指定一個(gè)變量或類型的對(duì)齊值。但是,不應(yīng)該要求該值小于基本對(duì)齊值。
_Alignas(float) char c1;
_Alignas(8) char c2;
C11在stdlib.h庫(kù)還添加了一個(gè)新的內(nèi)存分配函數(shù),用于對(duì)齊動(dòng)態(tài)分配的內(nèi)存。該函數(shù)的原型如下:
void * aligned_alloc(size_t alignment, size_t size);
第1個(gè)參數(shù)代表指定的對(duì)齊,第2個(gè)參數(shù)是所需的字節(jié)數(shù),其值應(yīng)是第1個(gè)參數(shù)的倍數(shù)。與其他內(nèi)存分配函數(shù)一樣,要使用free()函數(shù)釋放之前分配的內(nèi)存。