日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > 嵌入式 > 嵌入式大雜燴
[導(dǎo)讀]每天一點(diǎn)C / 位和字節(jié) 正文目錄: 1.?位相關(guān)的運(yùn)算符 2.?位相關(guān)的用法 3.?位字段?(bit?field) 4.?怎樣判斷機(jī)器的字節(jié)順序? 5.?怎樣將整數(shù)轉(zhuǎn)換到二進(jìn)制或十六進(jìn)制? 6.?怎樣高效地統(tǒng)計(jì)整數(shù)中為1的位的個(gè)數(shù)? 7.?相關(guān)參考 寫作目的: 記錄一些 C 語言中位和字


每天一點(diǎn)C / 位和字節(jié)

正文目錄:

1. 位相關(guān)的運(yùn)算符
2. 位相關(guān)的用法
3. 位字段 (bit field)
4. 怎樣判斷機(jī)器的字節(jié)順序?
5. 怎樣將整數(shù)轉(zhuǎn)換到二進(jìn)制或十六進(jìn)制?
6. 怎樣高效地統(tǒng)計(jì)整數(shù)中為1的位的個(gè)數(shù)?
7. 相關(guān)參考

寫作目的:

  • 記錄一些 C 語言中位和字節(jié)相關(guān)的操作。

測試環(huán)境:

  • Ubuntu 16.04
  • gcc version 5.4.0

1. 位相關(guān)的運(yùn)算符

1) 取反:~

~(10011010) =  (01100101)

運(yùn)算符 ~ 把 1 變?yōu)?0,把 0 變?yōu)?1。

2) 按位與:&

(10010011) & (00111101) = (00010001)

運(yùn)算符 & 通過逐位比較兩個(gè)運(yùn)算對象,生成一個(gè)新值。對于每個(gè)位,只有兩個(gè)運(yùn)算對象中相應(yīng)的位都為 1,結(jié)果才為 1。

3) 按位或:|

(10010011) | (00111101) = (10111111)

運(yùn)算符 | 通過逐位比較兩個(gè)運(yùn)算對象,生成一個(gè)新值。對于每個(gè)位,如果兩個(gè)運(yùn)算對象中有 >=1 的位為 1,結(jié)果就為 1。

4) 按位異或:^

(10010011) ^ (00111101) = (10101110)

運(yùn)算符 ^ 逐位比較兩個(gè)運(yùn)算對象。對于每個(gè)位,如果兩個(gè)運(yùn)算對象中有且只有 1 位 為 1, 結(jié)果為 1。

5) 左移:<<

(10001010) << 2 = (00101000)

運(yùn)算符 << 將其左側(cè)運(yùn)算對象每一位的值向左移動其右側(cè)運(yùn)算對象指定的位數(shù)。左側(cè)運(yùn)算對象移出左末端位的值會被丟棄,用 0 填充空出的位置

6) 右移:>>

(10001010) >> 2 = (00100010// 情況1
(10001010) >> 2 = (11100010// 情況2

運(yùn)算符 >> 將其左側(cè)運(yùn)算對象每一位的值向右移動其右側(cè)運(yùn)算對象指定的位數(shù)。左側(cè)運(yùn)算對象移出右末端位的值丟。

對于無符號類型,用 0 填充空出的位置。

對于有符號類型,其結(jié)果取決于機(jī)器??粘龅奈恢每赡苡?0 填充,也可能用符號位填充。


2. 位相關(guān)的用法

1) 什么是掩碼?

所謂掩碼指的是一些設(shè)置為開 (1) 或關(guān) (0) 的位組合。

為什么叫掩碼?看下面這個(gè)例子:

#define MASK (1<<1)
flags = flags & MASK;

上面這個(gè)例子中,只有 MASK 中 為1的位才可見,掩碼中的 0 隱藏 (掩蓋) 了 flags 中相應(yīng)的位。

mask.png

2) 打開 (設(shè)置) 位
有時(shí),比如在操作硬件寄存器的情況下,需要打開一個(gè)值中的特定位,同時(shí)保持其他位不變。這種情況可以使用按位或運(yùn)算符 | 和一個(gè)掩碼進(jìn)行配合:

#define MASK (1<<1)
flags |= MASK;

3) 關(guān)閉 (清空) 位
在不影響其他位的情況下關(guān)閉指定的位:

#define MASK (1<<1)
flags &= ~MASK;

4) 切換位
切換位指的是打開已關(guān)閉的位,或關(guān)閉已打開的位:

#define MASK (1<<1)
flags ^= MASK;

5) 檢查位
檢查某位的值是否為 1:

#define MASK (1<<1)
(flags & MASK) == MASK

注意,掩碼至少要與其覆蓋的值的寬度相同,要避免符號位帶來的意外,最好在代碼中使用 unsigned int 操作位和字節(jié)。

6) 提取位

移位運(yùn)算符可用于從較大單元中提取一些位,例如提取 RBG 顏色值:

#define BYTE_MASK 0xff
unsigned long color = 0x123456;
unsigned char blue, green, red;
red = color & BYTE_MASK;
green = (color >> 8) & BYTE_MASK;
blue = (color >> 16) & BYTE_MASK;

3. 位字段 ( bit field )

位字段通過一個(gè)結(jié)構(gòu)聲明來建立,該結(jié)構(gòu)聲明為每個(gè)字段提供標(biāo)簽,并確定該字段的寬度,在 Linux 驅(qū)動中,某些代碼使用了位字段:

struct ap_queue_status {
 unsigned int queue_empty : 1;
    ...
 unsigned int response_code : 8;
 unsigned int pad2  : 16;
} aqs;

給字段賦值:

aqs.queue_empty = 0;
aqs.response_code = 0xff;

所賦的值不能超出字段可容納的范圍。

位字段占用的空間:

struct {
    unsigned int autfd : 1;
    unsigned int bldfc : 1;
    unsigned int undln : 1;
    unsigned int itals : 1;
} prnt;

struct {
    unsigned int code1 : 2;
    unsigned int code2 : 2;
    unsigned int code3 : 6;
    unsigned int code4 : 8;
#if TEST
    unsigned int code5 : 10;
    unsigned int code6 : 12;
    unsigned int code7 : 24;
#endif
} prcode;

int main(void)
{
    printf("%ld %ld\n"sizeof(prnt), sizeof(prcode));
}

測試結(jié)果:

4 4     // without TEST
4 12    // with TEST

系統(tǒng)會自動判斷出需要幾個(gè) byte 的空間來存儲數(shù)據(jù),在我的機(jī)器上測試,一個(gè)成員最起碼占用 1 個(gè) byte。

位字段的儲存順序:
取決于機(jī)器。在有些機(jī)器上,存儲的順序是從左往右,而在另一些機(jī)器上,是從右往左。另外,不同的機(jī)器中兩個(gè)字段邊界的位置也有區(qū)別。由于這些原因,位字段通常都不容易移植,我不要求自己寫,但是要求自己會看


4. 怎樣判斷機(jī)器的字節(jié)順序?

演示 demo:

int main(void)
{
    int x = 1;
    
    if (*((char *)&x) == 1)
        printf("little - endian\n");
    else
        printf("big - endian\n");

    return 0;
}

運(yùn)行效果:

$ gcc byte_order.c -o byte_order
$ ./byte_order 
little - endian

代碼解析:

  • 先初始化在內(nèi)存中占用 4 個(gè)字節(jié)的 int 變量。

  • 然后獲取int 變量中第 1 個(gè)字節(jié)的地址,等效代碼是:char *px = (char *)&x。

  • 最后獲取第 1 個(gè)字節(jié)的值:*px,觀察 *px 是否為 1 就可以知道大小端了。


5. 怎樣將整數(shù)轉(zhuǎn)換到二進(jìn)制或十六進(jìn)制?

演示 demo:

進(jìn)行任意進(jìn)制數(shù)轉(zhuǎn)換的小函數(shù):

#define BUF_SIZE (33)
char *baseconv(unsigned int num,int base)
{
    static char retbuf[BUF_SIZE];
    char *p;
    
    ...

    p = &retbuf[sizeof(retbuf)-1];
    *p='\0';

    do {
        *--p="0123456789abcdef"[num % base];
        num /=base;
    } while(num !=0);

    return p;
}

在 main() 中進(jìn)行測試:

int main(void)
{
    int a = 20;

    printf("%s\n", baseconv(a, 2));
    printf("%s\n", baseconv(a, 16));
    
    return 0;
}

運(yùn)行效果:

$ gcc int_conv.c -o int_conv
$ ./int_conv 
10100
14

代碼解析:

  • 首先需要明確的是:整數(shù)本來就是以二進(jìn)制存儲的,這里說的轉(zhuǎn)換只是指打印的形式

  • 在baseconv() 中的緩沖是 static 的,這有2 個(gè)作用:1) 將緩沖清 0,2) 只有是 static 的緩沖才能在函數(shù)外部被使用。

  • 注意 char *p = &retbuf[sizeof(retbuf)-1]?。健?\0' 這個(gè)操作,這里將緩沖的最高位設(shè)置為字符串結(jié)束符,同時(shí)表明了字符串是從高地址向底地址構(gòu)造的,函數(shù)返回緩沖中有效數(shù)據(jù)的起始地址。

  • 如果你這樣打?。?/p>

    printf("%d %s %s\n", a, baseconv(a, 2), baseconv(a, 16));

    會得到這樣的結(jié)果:10100 00。

    這是因?yàn)椤aseconv() 中的緩沖是 static 的, baseconv(a, 2) 將 baseconv(a, 16) 沖刷掉了


6. 怎樣高效地統(tǒng)計(jì)整數(shù)中為1的位的個(gè)數(shù)?

演示 demo:

統(tǒng)計(jì)整數(shù)中為1的位的個(gè)數(shù)的小函數(shù):

static int bitcounts[] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};

int bitcount(unsigned int u)
{
    int n=0;

    for(; u!=0; u>>=4)
        n += bitcounts[u & 0x0f];

    return n;
}

在 main() 中進(jìn)行測試:

int main(void)
{
    int i = 0;

    for (i=0; i<=0x0f; i++)
        printf("%d\n", bitcount(i));

    return 0;
}

運(yùn)行效果:

$ gcc bit_counts.c -o bit_counts
$ ./bit_counts 
0
1
1
2
1
2
2
3
1
2
2
3
2
3
3
4

代碼解析:

  • 許多像這樣的位問題可以使用查找表格來提高效率和速度。

  • 這段代碼是以每次 4 位的方式計(jì)算數(shù)值中為1的位的個(gè)數(shù)。

相關(guān)參考

  • 《C Primer Plus 6th》, 15
  • 《你必須知道的 495 個(gè) C語言問題》, 20.7
  • 《C 和指針》, 5.1.3
  • 《C 專家》, NULL
  • 《C 和 C++ 程序員面試秘籍》, 5
  • 《C 語言解惑》, NULL

思考技術(shù),也要思考人生

學(xué)習(xí)技術(shù),更要學(xué)習(xí)如何生活。

你和我各有一個(gè)蘋果,如果我們交換蘋果的話,我們還是只有一個(gè)蘋果。但當(dāng)你和我各有一個(gè)想法,我們交換想法的話,我們就都有兩個(gè)想法了。

嵌入式系統(tǒng) (Linux、RTOS、OpenWrt、Android) 和 開源軟件 感興趣,想和更多人互相交流學(xué)習(xí),關(guān)注公眾號:嵌入式Hacker,一起來學(xué)習(xí)吧。

關(guān)注 / 轉(zhuǎn)發(fā) / 打賞,都是對作者莫大的支持。覺得文章對你有價(jià)值的話,不妨點(diǎn)個(gè) 在看和點(diǎn)贊 哦。祝工作順利,家庭幸福,財(cái)源滾滾~

猜你喜歡

C語言對象編程第一彈:封裝與抽象

請寫一個(gè)函數(shù)輸出如下波形

免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護(hù)是驅(qū)動電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機(jī)驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計(jì)工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉