Go位运算

原创
2017/10/27 11:48
阅读数 52

Go 位运算

&      位运算 AND
|      位运算 OR
^      位运算 XOR
&^     位清空 (AND NOT)
<<     左移
>>     右移

 

位运算 & 的应用

package main

import (
	"errors"
	"fmt"
)

func readUint64Revert(buff []byte, dest *uint64) error {
	if len(buff) != 8 {
		return errors.New("incorrect source byte array length")
	}

	*dest = uint64(buff[7] & 0xFF)
	*dest += uint64(buff[6]&0xFF) << 8
	*dest += uint64(buff[5]&0xFF) << 16
	*dest += uint64(buff[4]&0xFF) << 24
	*dest += uint64(buff[3]&0xFF) << 32
	*dest += uint64(buff[2]&0xFF) << 40
	*dest += uint64(buff[1]&0xFF) << 48
	*dest += uint64(buff[0]&0xFF) << 56

	return nil
}

func main() {

	mockData := []byte{0x2E, 0x4A, 0x3C, 0x00, 0x66, 0xD9, 0x1B, 0x1C}
	var result uint64
	err := readUint64Revert(mockData, &result)

	if err != nil {
		fmt.Println("error...")
		return
	}

	fmt.Println(result)

	buff := make([]byte, 4)

	buff[0] = 0
	buff[1] = 255

	fmt.Println(buff[0], buff[1])

	data01 := buff[0] & 0xff
	data02 := buff[1] & 0xff

	fmt.Println(data01, data02)
}

readUint64Revert 是从一个字节数组中读取一个 uint64 类型的整型。

其中 buff[7] & 0xFF 表示取字节数组的第8个元素和 0xFF 做 & 操作。

其中 0xFF 表示一个掩码,表示一个字的最低8位全是1。 比如,0x89ABCDEF & 0xFF = 0x000000EF。

 

位运算 ^ 的应用

按位异或运算定义,

1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0

异或的几个常见用途:

(1) 实现两个值的交换,而不必使用临时变量。如下代码,

package main

import "fmt"

func main() {
	a := 0xA7
	b := 0xA1

	fmt.Println(a, b)

	a ^= b
	b ^= a
	a ^= b

	fmt.Println(a, b)
}

 输出:

167 161
161 167

可以这样理解:

第一步  a^=b 即a=(a^b);

第二步  b^=a 即b=b^(a^b),由于^运算满足交换律,b^(a^b)=b^b^a。由于一个数和自己异或的结果为0并且任何数与0异或都会不变的,所以此时b被赋上了a的值。

第三步 a^=b 就是a=a^b,由于前面二步可知a=(a^b),b=a,所以a=a^b即a=(a^b)^a。故a会被赋上b的值。
再来个实例说明下以加深印象。int a = 13, b = 6;

a的二进制为 13=8+4+1=1101(二进制)

b的二进制为 6=4+2=110(二进制)

第一步 a^=b  a = 1101 ^ 110 = 1011;

第二步 b^=a  b = 110 ^ 1011 = 1101;即b=13

第三步 a^=b  a = 1011 ^ 1101 = 110;即a=6

(2) 在汇编语言中经常用于将变量置零:

package main

import "fmt"

func main() {
	a := 0xA7
	b := 0xA1

	fmt.Println(a, b)

	a ^= a
	b ^= b

	fmt.Println(a, b)
}

输出:

167 161
0 0

(3) 使某些特定的位翻转

例如对数10100001的第2位和第3位翻转,则可以将该数与00000110进行按位异或运算。

10100001^00000110 = 10100111

(4) 使用定理三进行编码解码

由B ^ A^ A = B,我们可以假设一聊天记录是B,密钥是A。现在B ^ A之后,成了密文了。为了解密,对密文再使用密钥A进行一次异或运算即可。也即是B ^ A^ A = B。

(5) 使用异或求一个数的绝对值

package main

import "fmt"

func main() {
	data := -1234
	i := data >> 31
	result := data ^ i - i
	fmt.Println(data, result)
}

 

位运算 &^ 的应用

此运算符是双目运算符,按位计算。主要功能:

将运算符左边数据相异的位保留,相同位清零。

	fmt.Println(0 &^ 0) //0
	fmt.Println(0 &^ 1) //0
	fmt.Println(1 &^ 0) //1
	fmt.Println(1 &^ 1) //0

==========END==========

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部