概述
Go的位操作
在计算机内存和处理能力都成本昂贵的时代,位操作是(在某些情况下是唯一的)一种被优先选择来处理信息的方式。即使在今天,直接的位操作在一些情况下同样也很重要。例如:低级系统编程,图像处理,密码学等。
Go编程语言支持以下几种位操作,包括:
&位与
|位或
^位异或
&^位清空
<<左移
>>右移
文章后面的部分将详细讨论每一种操作,以及举例说明它们如何使用。
&运算
在Go中,&操作表示两个整数按位AND
运算。AND
操作具有如下特性:
Given operands a,b
AND(a,b)=1;only if a=b=1
else=0
AND
操作可以有效的清除值为0的数位,例如,我们可以使用&
操作来清除最后4个最低有效位(LSB),使其为0。
func main(){
var x uint8=0xAC //x=10101100
x=x&0xF0 //x=10100000
}
所有的二进制操作都支持简短的复合赋值形式。例如上面的例子可以改写成:
func main(){
var x uint8=0xAC //x=10101100
x&=0xF0 //x=10100000
}
另外一个小技巧就是用&
操作来检测一个数是奇数还是偶数。这是因为奇数的最低有效位为1,而偶数的最低有效位为0。因此我们可以利用整数和数字1进行“与”运算,就可判断该数的奇偶性。
import (
"fmt"
"math/rand"
)
func main(){
for x:=0;x<100;x++{
num:=rand.Int()
if num&1==1{
fmt.Printf("%d is oddn",num)
}else{
fmt.Printf("%d is evenn",num)
}
}
}
| 运算
|
表示两个整数按位OR
,OR
操作具有如下特点。
Given operands a,b
OR(a,b)=1;when a=1 or b=1
else=0
我们可以使用OR
操作来有选择的设置给定整数的某个位。例如下面的例子,我们使用OR
了设置MSB(最高有效位),第7位和第三位的值为1。
func main(){
var a uint8=0
a|=196
fmt.Printf("%b",a)
}
使用位掩码技术对一个给定的整数值任意位设置时,OR
相当有用。例如,我们可以扩展之前的程序。下面的程序使用十进制的196和3来设置对应位。
func main(){
var a uint8=0
a|=196
a|=3
fmt.Printf("%b",a)
}
位作为配置信息
我们可以结合OR
和AND
两种操作符,作为指定配置值和分别读取它们的一种方法。下面的源代码简要的说明如何使用。函数procstr转化string类型的内容,它需要两个参数:第一个参数str表示待转换的字符串,第二个参数conf,是个整数。用来指定多个转化配置。
const (
UPPER = 1
LOWER = 2
CAP = 4 //首字母大写
REV = 8 //颠倒顺序
)
func main() {
fmt.Println(procstr("HELLO PEOPLE!", LOWER|REV|CAP))
}
func procstr(str string, conf byte) string {
//reverse string
rev := func(s string) string {
runes := []rune(s)
n := len(runes)
for i := 0; i < n/2; i++ {
runes[i], runes[n-1-i] = runes[n-1-i], runes[i]
}
return string(runes)
}
//query config bits
if (conf & UPPER) != 0 {
str = strings.ToUpper(str)
}
if (conf & LOWER) != 0 {
str = strings.ToLower(str)
}
if (conf & CAP) != 0 {
str = strings.Title(str)
}
if (conf & REV) != 0 {
str = rev(str)
}
return str
}
上面主函数中调用方法procstr(“HELLO PEOPLE”,LOWER|REV|CAP),将会把字符串“HELLO PEOPLE”转化为小写,单词首字母大写,然后颠倒字符串前后顺序。此时参数conf的值为14,它的第二,第三和第四位设置了转化的这些条件。然后,代码使用连续的if语句块来提取这些配置,并对字符串应用对应的字符串转化。
^操作
Go中用^
表示XOR
,它具有以下属性:
Given operands a,b
XOR(a,b)=1;only if a!=b
else=0
异或定义的含义是它可以将一个值切换到另一个。例如,给定的16位值,我们可以使用下面代码切换前8位(从最高有效位开始)。
func main(){
var a uint16=0xCEFF
a^=0xFF00 //same a=a^0xFF00
}
// a = 0xCEFF (11001110 11111111)
// a ^=0xFF00 (00110001 11111111)
XOR
的一个实际用途就是判定符号,(a^b)>=0判定两个数的符号是否相同。
func main(){
a,b:=-12,25
fmt.Println("a and b have same sign?",(a^b)>=0)
}
/*prints:
a and b have same sign? false */
^作为按位补码(NOT)
与其他语言不同(c/c++,Java,Python,Javascript等),Go没有一个专门的一元补码操作符来对值取反,代替的是XOR
操作符。
func main(){
var a byte=0x0F
fmt.Printf("%08bn",a)
fmt.Printf("%08bn",^a)
}
/* prints:
00001111 //var a
11110000 //^a
&^操作
&^
操作,也称AND NOT
,它是一个使用AND
和NOT
的简写形式,具有以下特征:
Given operands a,b
AND_NOT(a,b)=AND(a,NOT(b))
它有一个有趣的特性,那就是当第二个数设置为1,它就会清除第一个数。
AND_NOT(a,1)=0;clears a
AND_NOT(a,0)=a;
下面的代码使用AND NOT
操作来清除变量a的四个最低有效位。
func main(){
var a byte=0xAB
fmt.Printf("%08bn",a)
a &^=0x0F
fmt.Printf("%08bn",a)
}
/* prints:
10101011
10100000 */
<<和>>操作
类似于其他c派生语言,Go使用<<
和>>
来分别代表左移和右移操作。具体特点如下:
Given integer operands a and n,
a<<n;shifts all bits in a to the left n times
a>>n;shifts all bits in a to the right n times
例如下面的例子中将a的值左移了三次,每次都将其移动的结果打印出来说明他的用途。
func main(){
var a int8=3
fmt.Printf("%08bn",a)
fmt.Printf("%08bn",a<<1)
fmt.Printf("%08bn",a<<2)
fmt.Printf("%08bn",a<<3)
}
/*prints:
00000011
00000110
00001100
00011000 */
记住每次移动,最低有效位用0填充,相反的,使用右移操作位时,最高有效位用0填充。(但是有符号位有些区别,详见文章后面的算数移位)
func main(){
var a int8=120
fmt.Printf("%08bn",a)
fmt.Printf("%08bn",a>>1)
fmt.Printf("%08bn",a>>2)
fmt.Printf("%08bn",a>>3)
}
/*prints:
01111000
00111100
00011110
00001111 */
左移和右移操作的小技巧是可以在乘除法用算时,每次操作表示对原数进行乘以2或除以2例如下面将200右移一位,表示将其除以2。
func main(){
a:=200
fmt.Printf("%dn",a>>1)
}
/*prints:
100 */
或者用左移2位,表示乘以4。例如
func main(){
a:=12
fmt.Printf("%dn",a<<2)
}
/* prints:
48 */
位移操作给我们提供了一种有趣的方式来操作二进制值的指定位。例如下面的例子中用|
和<<
操作来设置变量a的第三位。
func main(){
var a int8=8
fmt.Printf("%08bn",a)
a=a|(1<<2)
fmt.Printf("%08bn",a)
}
/*prints:
00001000
00001100 */
或者你可以将其与&
操作结合起来,测试第n位的值是否被设置。
func main(){
var a int8=12
if a&(1<<2)!={
fmt.Println("take action")
}
}
/* prints:
take action */
利用&^
和移位操作,我们将第n位的值不设置。例如下面的例子将变量a的第3位没有设置。
func main(){
var a int8=13
fmt.Printf("%04bn",a)
a=a&^(1<<2)
fmt.Printf("%04bn",a)
}
/* prints:
1101
1001 */
算数移位
当一个有符号值(左移)移位时,Go自动使用算数移位。在右移操作中,符号位被拷贝(或者扩展)来填充移动的位置。
结论
与其他现代语言一样,Go也支持所有的位操作。这篇文章仅仅提供了一些有关位操作的简单例子。你可以在由Sean Eron Anderson写的Bit Twiddling Hacks文章中发掘更多诀窍。
最后
以上就是义气电话为你收集整理的Go的位操作的全部内容,希望文章能够帮你解决Go的位操作所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复