嵌入式linux C語言(一) 位運算的使用

2021-09-19 16:00:28 字數 4759 閱讀 7676

嵌入式linux c語言(一)——位運算的使用

arm是記憶體與io統一編址,soc中有很多控制暫存器,通過對這些暫存器進行位運算對這些控制暫存器進行設定,進而控制外設功能。在修改暫存器某些位的過程中不能修改其他的位。

c語言基本的位操作符有與、或、異或、取反、左移、右移六種位運算子。如下表所示:

符號描述

運算規則                       

與兩個位都為1時,結果才為1

或    

兩個位都為0時,結果才為0

異或兩個位相同為0,相異為1

取反0變1,1變0

左移各二進位全部左移若干位,高位丟棄,低位補0

右移各二進位全部右移若干位,對無符號數,高位補0,有符號數,各編譯器處理方法不一樣,有的補符號位(算術右移),有的補0(邏輯右移)

位運算使用說明:

1、六種位運算只能用於整型資料,對float和double型別進行位操作會被編譯器報錯。

2、邏輯運算與位運算的區別:邏輯運算是將參與運算的兩個表示式整體的結果進行邏輯運算,而位運算是將參與運算的兩個資料,按對應的二進位制數逐位進行邏輯運算。邏輯運算子有邏輯與&&、邏輯或||、邏輯非!,位運算則有六種運算子,位與&、位或|、位異或^、位取反~、位左移<<、位右移》。

3、如果左移位數》=型別長度,在gcc環境下,gcc編譯器會報警告,但實際左移位數為左移位數%(8 * sizeof(int))。例如:

int i = 1, j = 0x80000000; //設int為32位

i = i << 33;   // 33 % 32 = 1 左移1位,i變成2

j = j << 33;   // 33 % 32 = 1 左移1位,j變成0,最高位被丟棄

4、在c語言中,左移是邏輯/算術左移(兩者完全相同),右移是算術右移,會保持符號位不變。左移時總是移位和補零。右移時無符號數是移位和補零,此時稱為邏輯右移;而有符號數大多數情況下是移位和補最左邊的位(也就是補最高有效位),移幾位就補幾位,此時稱為算術右移。 算術移位是相對於邏輯移位,它們在左移操作中都一樣,低位補0即可,但在右移中邏輯移位的高位補0而算術移位的高位是補符號位。

右移對符號位的處理和左移不同,對於有符號整數來說,比如int型別,右移會保持符號位不變。符號位向右移動後,正數的話補0,負數補1,也就是組合語言中的算術右移。當移動的位數超過型別的長度時,會取餘數,然後移動餘數個位。

int i = 0x80000000;

i = i >> 1;  //i的值不會變成0x40000000,而會變成0xc0000000

5、位操作符的運算優先順序比較低,因為盡量使用括號來確保運算順序,否則很可能會得到莫明其妙 的結果。比如要得到像1,3,5,9這些2^i+1的數字。寫成int a = 1 << i + 1;是不對的,程式會先執行i + 1,再執行左移操作。應該寫成int a = (1 << i) + 1。

位與運算的實質是將參與運算的兩個資料,按對應的二進位制數逐位進行邏輯與運算。典型應用如下:

a、特定資料段清零

快速對某一段資料單元的資料清零

unsigned int a = 0x00ff1278;

a &= 0xffff0fff;//對a的bit12--bit15位進行清零,a=0x00ff0278

//a &= ~(0xf<<12) ;//對a的bit12--bit15位進行清零,a=0x00ff0278

b、保留資料區的特定位

unsigned int a = 0x00ff1278;

a &= (0xf<<12);//保留a的bit12--bit15位,其他清零,a=0x00001000

c、判斷奇偶數

只要根據最未位是0還是1來決定,為0就是偶數,為1就是奇數。因此可以用if ((a & 1) == 0)代替if (a % 2 == 0)來判斷a是不是偶數

位或運算的實質是將參與運算的兩個資料,按對應的二進位制數逐位進行邏輯或運算。典型應用如下:

a、對資料位置1

unsigned int a = 0x00ff0278;

a |= 0x0000f000;//對a的第12-15位置1,a=0x00fff278

//a |= (0xf<<12);//對a的第12-15位置1,a=0x00fff278

位異或運算的實質是將參與運算的兩個資料,按對應的二進位制數逐位進行邏輯異或運算。只有當對應位的二進位制數互斥的時候,對應位的結果才為真。典型應用如下:

a、特定位取反

設定乙個資料的指定位,將1換為0,0換為1。例如整型數a=321,,將其低八位資料進行翻位的操作為a=a^0xff。

b、數值交換

a=a^b;

b=b^a;

a=a^b;

不使用第三方變數可以用位操作來實現交換兩數

位非運算的實質是將參與運算的兩個資料,按對應的二進位制數逐位進行邏輯非運算。

a、變換符號

變換符號只需要取反後加1

左移運算的實質是將對應的資料的二進位制值逐位左移若干位,並在空出的位置上填0,最高位溢位並捨棄。

位右移運算的實質是將對應的資料的二進位制值逐位右移若干位,並捨棄出界的數字。如果當前的數為無符號數,高位補零。

如果當前的資料為有符號數,在進行右移的時候,根據符號位決定左邊補0還是補1。如果符號位為0,則左邊補0;但是如果符號位為1,則根據不同的計算機系統,可能有不同的處理方式。可以看出位右移運算,可以實現對除數為2的整除運算。

提示 將所有對2的整除運算轉換為位移運算,可提高程式的執行效率。

a、求絕對值

int i = a >> 31;  

return i == 0 ? a : (~a + 1);  

或int i = a >> 31;  

return ((a ^ i) - i); 

a、將暫存器指定位(第n位置為1

gpxx |= (1b、將暫存器指定位(第n位置為0

gpxx &= ~(1《將暫存器的第n位清0,而又不影響其它位的現有狀態。

gpxx &= ~(1<<4 )

c、嵌入式開發位操作例項

unsigned int i = 0x00ff1234;

//i |= (0x1<<13);//bit13置1

//i |= (0xf<<4);//bit4-bit7置1

//i &= ~(1<<17);//清除bit17

//i &= ~(0x1f<<12);//清除bit12開始的5位

//取出bit3-bit8

//i &= (0x3f<<3);//保留bit3-bit8,其他位清零

//i >>= 3;//右移3位

//給暫存器的bit7-bit17賦值937

//i &= ~(0x7ff<<7);//bit7-bit17清零

//i |= (937<<7);//bit7-bit17賦值

//將暫存器bit7-bit17的值加17

// unsigned int a = i;//將a作為i的副本,避免i的其他位被修改

// a &= (0x7ff<<7);//取出bit7-bit17

//a >>= 7;//

// a += 17;//加17

// i &= ~(0x7ff<<7);//將i的bit7-bit17清零

// i |= (a<<7);//將+17後的數寫入bit7-bit17,其他位不變

//給乙個暫存器的bit7-bit17賦值937,同時給bit21-bit25賦值17

i &= ~((0x7ff<<7) | (0x1f<<21));//bit7-bit17、bit21-bit25清零

i |= ((937<<7) | (17<<21));//bit7-bit17、bit21-bit25賦值

//用巨集定義將32位數x的第n位(bit0為第1位)置位

#define set_bit_n(x,n) (x | (1u<<(n-1)))

//用巨集定義將32位數x的第n位(bit0為第1位)清零

#define clear_bit_n(x,n) (x & (~(1u<<(n-1))))

//用巨集定義將32位數x的第n位到第m位(bit0為第1位)置位

#define set_bits_n_m(x,n,m) (x | (((~0u)>>(32-(m-n+1)))<<(n-1)))

//用巨集定義將32位數x的第n位到第m位(bit0為第1位)清零

#define clear_bits_n_m(x,n,m) (x & (~(((~0u)>>(32-(m-n+1)))<<(n-1))))

//用巨集定義獲取32位數x的第n位到第m位(bit0為第1位)的部分

#define get_bits_n_m(x,n,m) ((x & ~(~(0u)<<(m-n+1))<<(n-1))>>(n-1))

嵌入式Linux C(二)

tab 命令不全,常用 ctrl c 終止正在執行的程式 ctrl d 退出執行介面 ctrl alt t 在當前終端新建標籤頁 linux 常用命令 useradd usedel passwd su groupadd groupdel ls cd touch cp mv rm chmod mkdi...

嵌入式Linux C程式設計

一 前言 一切,都想從不一樣做起。大學,原以為會和我當時高中想象的那樣,可以談場轟轟烈烈的戀愛,可以自由自在的旅行,可以忘乎所以,盡己之所興。如今,大三結束。驀然回首,卻發現自己浪費了那麼多改變自己的機會。如今,大學只剩最後一年,我要用這最後的時間去彌補曾經所浪費的一切,從現在開始,朝著自己的目標勇...

嵌入式Linux c 基礎

資料型別 向計算機申請儲存資料的記憶體大小,如int 申請4位元組的大小。變數是用來儲存值的所在處,它們有名字和資料型別.變數的資料型別決定了如何將代表這些值的位儲存到計算機的記憶體中 試卷的筆記 電腦是x86 裸機是arm 編譯程式 gcc 和 arm linux gcc 字串表示 反斜槓要必須雙...