我是靠谱客的博主 义气电话,这篇文章主要介绍Go的位操作,现在分享给大家,希望可以做个参考。

Go的位操作

在计算机内存和处理能力都成本昂贵的时代,位操作是(在某些情况下是唯一的)一种被优先选择来处理信息的方式。即使在今天,直接的位操作在一些情况下同样也很重要。例如:低级系统编程,图像处理,密码学等。
Go编程语言支持以下几种位操作,包括:

复制代码
1
2
3
4
5
6
&位与 |位或 ^位异或 &^位清空 <<左移 >>右移

文章后面的部分将详细讨论每一种操作,以及举例说明它们如何使用。

&运算

在Go中,&操作表示两个整数按位AND运算。AND操作具有如下特性:

复制代码
1
2
3
Given operands a,b AND(a,b)=1;only if a=b=1 else=0

AND操作可以有效的清除值为0的数位,例如,我们可以使用&操作来清除最后4个最低有效位(LSB),使其为0。

复制代码
1
2
3
4
func main(){ var x uint8=0xAC //x=10101100 x=x&0xF0 //x=10100000 }

所有的二进制操作都支持简短的复合赋值形式。例如上面的例子可以改写成:

复制代码
1
2
3
4
func main(){ var x uint8=0xAC //x=10101100 x&=0xF0 //x=10100000 }

另外一个小技巧就是用&操作来检测一个数是奇数还是偶数。这是因为奇数的最低有效位为1,而偶数的最低有效位为0。因此我们可以利用整数和数字1进行“与”运算,就可判断该数的奇偶性。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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) } } }

| 运算

|表示两个整数按位OROR操作具有如下特点。

复制代码
1
2
3
Given operands a,b OR(a,b)=1;when a=1 or b=1 else=0

我们可以使用OR操作来有选择的设置给定整数的某个位。例如下面的例子,我们使用OR了设置MSB(最高有效位),第7位和第三位的值为1。

复制代码
1
2
3
4
5
func main(){ var a uint8=0 a|=196 fmt.Printf("%b",a) }

使用位掩码技术对一个给定的整数值任意位设置时,OR相当有用。例如,我们可以扩展之前的程序。下面的程序使用十进制的196和3来设置对应位。

复制代码
1
2
3
4
5
6
func main(){ var a uint8=0 a|=196 a|=3 fmt.Printf("%b",a) }

位作为配置信息

我们可以结合ORAND两种操作符,作为指定配置值和分别读取它们的一种方法。下面的源代码简要的说明如何使用。函数procstr转化string类型的内容,它需要两个参数:第一个参数str表示待转换的字符串,第二个参数conf,是个整数。用来指定多个转化配置。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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,它具有以下属性:

复制代码
1
2
3
Given operands a,b XOR(a,b)=1;only if a!=b else=0

异或定义的含义是它可以将一个值切换到另一个。例如,给定的16位值,我们可以使用下面代码切换前8位(从最高有效位开始)。

复制代码
1
2
3
4
5
6
7
func main(){ var a uint16=0xCEFF a^=0xFF00 //same a=a^0xFF00 } // a = 0xCEFF (11001110 11111111) // a ^=0xFF00 (00110001 11111111)

XOR的一个实际用途就是判定符号,(a^b)>=0判定两个数的符号是否相同。

复制代码
1
2
3
4
5
6
7
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操作符。

复制代码
1
2
3
4
5
6
7
8
9
func main(){ var a byte=0x0F fmt.Printf("%08bn",a) fmt.Printf("%08bn",^a) } /* prints: 00001111 //var a 11110000 //^a

&^操作

&^操作,也称AND NOT,它是一个使用ANDNOT的简写形式,具有以下特征:

复制代码
1
2
Given operands a,b AND_NOT(a,b)=AND(a,NOT(b))

它有一个有趣的特性,那就是当第二个数设置为1,它就会清除第一个数。

复制代码
1
2
AND_NOT(a,1)=0;clears a AND_NOT(a,0)=a;

下面的代码使用AND NOT操作来清除变量a的四个最低有效位。

复制代码
1
2
3
4
5
6
7
8
9
10
func main(){ var a byte=0xAB fmt.Printf("%08bn",a) a &^=0x0F fmt.Printf("%08bn",a) } /* prints: 10101011 10100000 */

<<和>>操作

类似于其他c派生语言,Go使用<<>>来分别代表左移和右移操作。具体特点如下:

复制代码
1
2
3
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的值左移了三次,每次都将其移动的结果打印出来说明他的用途。

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
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填充。(但是有符号位有些区别,详见文章后面的算数移位)

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
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。

复制代码
1
2
3
4
5
6
7
func main(){ a:=200 fmt.Printf("%dn",a>>1) } /*prints: 100 */

或者用左移2位,表示乘以4。例如

复制代码
1
2
3
4
5
6
7
func main(){ a:=12 fmt.Printf("%dn",a<<2) } /* prints: 48 */

位移操作给我们提供了一种有趣的方式来操作二进制值的指定位。例如下面的例子中用|<<操作来设置变量a的第三位。

复制代码
1
2
3
4
5
6
7
8
9
10
func main(){ var a int8=8 fmt.Printf("%08bn",a) a=a|(1<<2) fmt.Printf("%08bn",a) } /*prints: 00001000 00001100 */

或者你可以将其与&操作结合起来,测试第n位的值是否被设置。

复制代码
1
2
3
4
5
6
7
8
9
func main(){ var a int8=12 if a&(1<<2)!={ fmt.Println("take action") } } /* prints: take action */

利用&^和移位操作,我们将第n位的值不设置。例如下面的例子将变量a的第3位没有设置。

复制代码
1
2
3
4
5
6
7
8
9
10
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内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(89)

评论列表共有 0 条评论

立即
投稿
返回
顶部