單片機的C語言中位操作用法
1、位運算符
本文引用地址:http://m.butianyuan.cn/article/201611/321750.htmC51提供了幾種位操作符,如下表所示:
運算符 | 含義 | 運算符 | 含義 |
& | 按位與 | ~ | 取反 |
| | 按位或 | << | 左移 |
^ | 按位異或 | >> | 右移 |
1)“按位與”運算符(&)
參加運算的兩個數(shù)據(jù),按二進位進行“與”運算。原則是全1為1,有0為0,即:
0&0=0; 0&1=0; 1&0=0; 1&1=1;
如下例:
a=5&3; //a=(0b 0101) & (0b 0011) =0b 0001 =1
那么如果參加運算的兩個數(shù)為負數(shù),又該如何算呢?會以其補碼形式表示的二進制數(shù)來進行與運算。
a=-5&-3; //a=(0b 1011) & (0b1101) =0b 1001 =-7
在實際的應(yīng)用中與操作經(jīng)常被用于實現(xiàn)特定的功能:
1.清零
“按位與”通常被用來使變量中的某一位清零。如下例:
a=0xfe; //a=0b 11111110
a=a&0x55;
//使變量a的第1位、第3位、第5位、第7位清零a= 0b 01010100
2.檢測位
要知道一個變量中某一位是‘1’還是‘0’,可以使用與操作來實現(xiàn)。
a=0xf5; //a=0b 11110101
result=a&0x08; //檢測a的第三位,result=0
3.保留變量的某一位
要屏蔽某一個變量的其它位,而保留某些位,也可以使用與操作來實現(xiàn)。
a=0x55; //a=0b 01010101
a=a&0x0f; //將高四位清零,而保留低四位a=0x05
2)“按位或”運算符(|)
參與或操作的兩個位,只要有一個為‘1’,則結(jié)果為‘1’。即有‘1’為‘1’,全‘0’為‘0’。
0|0=0; 0|1=1; 1|0=1; 1|1=1;
例如:
a=0x30|0x0f; //a=(0b00110000)|(0b00001111)=(0b00111111)=0x3f
“按位或”運算最普遍的應(yīng)用就是對一個變量的某些位置‘1’。如下例:
a=0x00; //a=0b 00000000
a=a|0x7f; //將a的低7位置為1,a=0x7f
3)“異或”運算符(^)
異或運算符^又被稱為XOR運算符。當參與運算的兩個位相同(‘1’與‘1’或‘0’與‘0’)時結(jié)果為‘0’。不同時為‘1’。即相同為0,不同為1。
0^0=0; 0^1=1; 1^0=1;1^1=0;
例如:
a=0x55^0x3f; //a=(0b01010101)^(0b00111111)=(0b01101010)=0x6a
異或運算主要有以下幾種應(yīng)用:
1.翻轉(zhuǎn)某一位
當一個位與‘1’作異或運算時結(jié)果就為此位翻轉(zhuǎn)后的值。如下例:
a=0x35; //a=0b00110101
a=a^0x0f; //a=0b00111010 a的低四位翻轉(zhuǎn)
關(guān)于異或的這一作用,有一個典型的應(yīng)用,即取浮點的相反數(shù),具體的實現(xiàn)如下:
f=1.23; //f為浮點型變量 值為1.23
f=f*-1; //f乘以-1,實現(xiàn)取其相反數(shù),要進行一次乘運算
f=1.23;
((unsigned char *)&f)[0]^=0x80; //將浮點數(shù)f的符號位進行翻轉(zhuǎn)實現(xiàn)取相反數(shù)
2.保留原值
當一個位與‘0’作異或運算時,結(jié)果就為此位的值。如下例:
a=0xff; //a=0b11111111
a=a^0x0f; //a=0b11110000與0x0f作異或,高四位不變,低四位翻轉(zhuǎn)
3.交換兩個變量的值,而不用臨時變量
要交換兩個變量的值,傳統(tǒng)的方法都需要一個臨時變量。實現(xiàn)如下:
void swap(unsigned char *pa,unsigned char *pb)
{
unsigned char temp=*pa;//定義臨時變量,將pa指向的變量值賦給它
*pa=*pb;
*pb=temp; //變量值對調(diào)
}
而使用異或的方法來實現(xiàn),就可以不用臨時變量,如下:
void swap_xor(unsigned char *pa,unsigned char *pb)
{
*pa=*pa^*pb;
*pb=*pa^*pb;
*pa=*pa^*pb; //采用異或?qū)崿F(xiàn)變量對調(diào)
}
從上例中可以看到異或運算在開發(fā)中是非常實用和神奇的。
4)“取反”運算符(~)
與其它運算符不同,“取反”運算符為單目運算符,即它的操作數(shù)只有一個。它的功能就是對操作數(shù)按位取反。也就是是‘1’得‘0’,是‘0’得‘1’。
~1=0; ~0=1;
如下例:
a=0xff; //a=0b11111111
a=~a; //a=0b00000000
1.對小于0的有符號整型變量取相反數(shù)
d=-1;
//d為有符號整型變量,賦值為-1,內(nèi)存表示為0b 11111111 11111111
d=~d+1; //取d的相反數(shù),d=1,內(nèi)存表示0b 00000000 00000001
此例運用了負整型數(shù)在內(nèi)存以補碼方式來存儲的這一原理來實現(xiàn)的。負數(shù)的補碼方式是這樣的:負數(shù)的絕對值的內(nèi)存表示取反加1,就為此負數(shù)的內(nèi)存表示。如-23如果為八位有符號整型數(shù),則其絕對值23的內(nèi)存表示為0b00010111,對其取反則為0b11101000,再加1為0b11101001,即為0XE9,與Keil仿真結(jié)果是相吻合的:
2.增強可移植性
關(guān)于“增強可移植性”用以下實例來講解:
假如在一種單片機中unsigned char類型是八個位(1個字節(jié)),那么一個此類型的變量a=0x67,對其最低位清零。則可以用以下方法:
a=0x67; //a=0b 0110 0111
a=a&0xfe; //a=0b 0110 0110
上面的程序似乎沒有什么問題,使用0xfe這一因子就可以實現(xiàn)一個unsigned char型的變量最低位清零。但如果在另一種單片機中的unsigned char類型被定義為16個位(兩個字節(jié)),那么這種方法就會出錯,如下:
b=0x6767; //假設(shè)b為另一種單片機中的unsigned char類型變量,值為0b 0110 0111 0110 0111
b=b&0xfe; //如果此時因子仍為0xfe的話,則結(jié)果就為0b 0000 0000 0110 0110即0x0066,而與0x6766不相吻合
上例中的問題就是因為不同環(huán)境中的數(shù)據(jù)類型差異所造成的,即程序的可移植性不好。對于這種情況可以采用如下方法來解決:
a=0x67; //a=0b 0110 0111
a=a&~1; //在不同的環(huán)境中~1將自動匹配運算因子,實現(xiàn)最后一位清零 a=0x66其中~1為0b 11111110
b=0x6767; //a=0b 0110 0111 0110 0111
b=a&~1; //~1=0b 1111 1111 1111 1110,b=0b 0110 0111 0110 0110,即0x6766
5)左移運算符(<<)
左移運算符用來將一個數(shù)的各位全部向左移若干位。如:
a=a<<2
表示將a的各位左移2位,右邊補0。如果a=34(0x22或0b00100010),左移2位得0b10001000,即十進制的136。高位在左移后溢出,不起作用。
從上例可以看到,a被左移2位后,由34變?yōu)榱?36,是原來的4倍。而如果左移1位,就為0b01000100,即十進制的68,是原來的2倍,很顯然,左移N位,就等于乘以了2N。但一結(jié)論只適用于左移時被溢出的高位中不包含‘1’的情況。比如:
a=64; //a=0b 0100 0000
a=a<<2; //a=0b 0000 0000
其實可以這樣來想,a為unsigned char型變量,值為64,左移2位后等于乘以了4,即64X4=256,而此種類型的變量在表達256時,就成為了0x00,產(chǎn)生了一個進位,即溢出了一個‘1’。
在作乘以2N這種操作時,如果使用左移,將比用乘法快得多。因此在程序中適應(yīng)的使用左移,可以提高程序的運行效率。
6)右移運算符
右移與左移相類似,只是位移的方向不同。如:
a=a>>1
表示將a的各位向右移動1位。與左移相對應(yīng)的,左移一位就相當于除以2,右移N位,就相當于除以2N。
在右移的過程中,要注意的一個地方就是符號位問題。對于無符號數(shù)右移時左邊高位移和‘0’。對于有符號數(shù)來說,如果原來符號位為‘0’,則左邊高位為移入‘0’,而如果符號位為‘1’,則左邊移入‘0’還是‘1’就要看實際的編譯器了,移入‘0’的稱為“邏輯右移”,移入‘1’的稱為“算術(shù)右移”。Keil中采用“算術(shù)右移”的方式來進行編譯。如下:
d=-32; //d為有符號整型變量,值為-32,內(nèi)存表示為0b 11100000
d=d>>1;//右移一位d為0b 11110000即-16,Keil采用"算術(shù)邏輯"進行編譯
7)位運算賦值運算符
在對一個變量進行了位操作中,要將其結(jié)果再賦給該變量,就可以使用位運算賦值運算符。位運算賦值運算符如下:
&=, |=,^=,~=,<<=, >>=
例如:a&=b相當于a=a&b,a>>=2相當于a>>=2。
8)不同長度的數(shù)據(jù)進行位運算
如果參與運算的兩個數(shù)據(jù)的長度不同時,如a為char型,b為int型,則編譯器會將二者按右端補齊。如果a為正數(shù),則會在左邊補滿‘0’。若a為負數(shù),左邊補滿‘1’。如果a為無符號整型,則左邊會添滿‘0’。
a=0x00; //a=0b 00000000
d=0xffff; //d=0b 11111111 11111111
d&=a; //a為無符號型,左邊添0,補齊為0b 00000000 00000000,d=0b 00000000 00000000
評論