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
的過程中一直是負數。