Swift位運算符
位運算符
位操作符通常在諸如圖像處理和創建設備驅動等底層開發中使用,使用它可以單獨操作數據結構中原始數據的比特位。在使用一個自定義的協議進行通信的時候,運用位運算符來對原始數據進行編碼和解碼也是非常有效的。
Swift支持如下所有C語言的位運算符:
按位取反運算符
按位取反運算符~
對一個操作數的每一位都取反。
這個運算符是前置的,所以請不加任何空格地寫着操作數之前。
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // 等於 0b11110000
UInt8
是8位無符整型,可以存儲0~255之間的任意數。這個例子初始化一個整型爲二進制值00001111
(前4位爲0
,後4位爲1
),它的十進制值爲15
。
使用按位取反運算~
對initialBits
操作,然後賦值給invertedBits
這個新常量。這個新常量的值等於所有位都取反的initialBits
,即1
變成0
,0
變成1
,變成了11110000
,十進制值爲240
。
按位與運算符
按位與運算符對兩個數進行操作,然後返回一個新的數,這個數的每個位都需要兩個輸入數的同一位都爲1時才爲1。
以下代碼,firstSixBits
和lastSixBits
中間4個位都爲1。對它倆進行按位與運算後,就得到了00111100
,即十進制的60
。
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // 等於 00111100
按位或運算
按位或運算符|
比較兩個數,然後返回一個新的數,這個數的每一位設置1的條件是兩個輸入數的同一位都不爲0(即任意一個爲1,或都爲1)。
如下代碼,someBits
和moreBits
在不同位上有1
。按位或運行的結果是11111110
,即十進制的254
。
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // 等於 11111110
按位異或運算符
按位異或運算符^
比較兩個數,然後返回一個數,這個數的每個位設爲1
的條件是兩個輸入數的同一位不同,如果相同就設爲0
。
以下代碼,firstBits
和otherBits
都有一個1
跟另一個數不同的。所以按位異或的結果是把它這些位置爲1
,其他都置爲0
。
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // 等於 00010001
按位左移/右移運算符
左移運算符<<
和右移運算符>>
會把一個數的所有比特位按以下定義的規則向左或向右移動指定位數。
按位左移和按位右移的效果相當把一個整數乘於或除於一個因子爲2
的整數。向左移動一個整型的比特位相當於把這個數乘於2
,向右移一位就是除於2
。
無符整型的移位操作
對無符整型的移位的效果如下:
已經存在的比特位向左或向右移動指定的位數。被移出整型存儲邊界的的位數直接拋棄,移動留下的空白位用零0
來填充。這種方法稱爲邏輯移位。
以下這張把展示了 11111111 << 1
(11111111
向左移1位),和 11111111 >> 1
(11111111
向右移1位)。藍色的是被移位的,灰色是被拋棄的,橙色的0
是被填充進來的。
let shiftBits: UInt8 = 4 // 即二進制的00000100
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
你可以使用移位操作進行其他數據類型的編碼和解碼。
let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC, 即 204
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66, 即 102
let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即 153
這個例子使用了一個UInt32
的命名爲pink
的常量來存儲層疊樣式表CSS
中粉色的顏色值,CSS
顏色#CC6699
在Swift用十六進制0xCC6699
來表示。然後使用按位與(&)和按位右移就可以從這個顏色值中解析出紅(CC),綠(66),藍(99)三個部分。
對0xCC6699
和0xFF0000
進行按位與&
操作就可以得到紅色部分。0xFF0000
中的0
了遮蓋了OxCC6699
的第二和第三個字節,這樣6699
被忽略了,只留下0xCC0000
。
然後,按向右移動16位,即 >> 16
。十六進制中每兩個字符是8比特位,所以移動16位的結果是把0xCC0000
變成0x0000CC
。這和0xCC
是相等的,都是十進制的204
。
同樣的,綠色部分來自於0xCC6699
和0x00FF00
的按位操作得到0x006600
。然後向右移動8們,得到0x66
,即十進制的102
。
最後,藍色部分對0xCC6699
和0x0000FF
進行按位與運算,得到0x000099
,無需向右移位了,所以結果就是0x99
,即十進制的153
。
有符整型的移位操作
有符整型的移位操作相對複雜得多,因爲正負號也是用二進制位表示的。(這裏舉的例子雖然都是8位的,但它的原理是通用的。)
有符整型通過第1個比特位(稱爲符號位)來表達這個整數是正數還是負數。0
代表正數,1
代表負數。
其餘的比特位(稱爲數值位)存儲其實值。有符正整數和無符正整數在計算機裏的存儲結果是一樣的,下來我們來看+4
內部的二進制結構。
符號位爲0
,代表正數,另外7比特位二進制表示的實際值就剛好是4
。
負數呢,跟正數不同。負數存儲的是2的n次方減去它的絕對值,n爲數值位的位數。一個8比特的數有7個數值位,所以是2的7次方,即128。
我們來看-4
存儲的二進制結構。
現在符號位爲1
,代表負數,7個數值位要表達的二進制值是124,即128 - 4。
負數的編碼方式稱爲二進制補碼錶示。這種表示方式看起來很奇怪,但它有幾個優點。
首先,只需要對全部8個比特位(包括符號)做標準的二進制加法就可以完成 -1 + -4
的操作,忽略加法過程產生的超過8個比特位表達的任何信息。
第二,由於使用二進制補碼錶示,我們可以和正數一樣對負數進行按位左移右移的,同樣也是左移1位時乘於2
,右移1位時除於2
。要達到此目的,對有符整型的右移有一個特別的要求:
對有符整型按位右移時,使用符號位(正數爲0
,負數爲1
)填充空白位。
這就確保了在右移的過程中,有符整型的符號不會發生變化。這稱爲算術移位。
正因爲正數和負數特殊的存儲方式,向右移位使它接近於0
。移位過程中保持符號會不變,負數在接近0
的過程中一直是負數。