重溫C語(yǔ)言(9)之位運(yùn)算

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 = 1111111011111110-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é)果是 0010010011100100, 根據(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)存。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容