首页
技术博客
PHP教程
数据库技术
前端开发
HTML5
Nginx
php论坛
新用户注册
|
会员登录
PHP教程
技术博客
编程问答
PNG素材
编程语言
前端技术
Android
PHP教程
HTML5教程
数据库
Linux技术
Nginx技术
PHP安全
WebSerer
职场攻略
JavaScript
开放平台
业界资讯
大话程序猿
登录
极速注册
取消
热门标签 | HotTags
replace
jsp
sum
integer
copy
include
dll
frameworks
tree
substring
search
go
perl
main
audio
hashset
dagger
expression
hash
python2
bit
actionscrip
split
install
bash
bytecode
数组
cPlusPlus
triggers
php8
match
java
get
php7
char
php5
python
int
hashcode
stream
testing
subset
config
plugins
object
yaml
timestamp
typescript
grid
rsa
cpython
format
heatmap
python3
cookie
schema
js
node.js
uml
byte
instance
range
fetch
foreach
regex
netty
loops
request
httpclient
string
tags
runtime
uri
hashtable
httprequest
filter
express
default
ip
当前位置:
开发笔记
>
编程语言
> 正文
深入解析Go语言中的位操作技术
作者:多少年都不会变 | 来源:互联网 | 2024-10-26 11:29
![cover](https://raw.githubusercontent.com/studygolang/gctt-images/master/go-bits/cover.png)
在以前内存和处理能力(CPU)都是非常昂贵的,于是直接在位上编程就成为了处理信息的首选方式(在有些情况下也是唯一的方式)。如今,直接对位进行操作在底层系统、图像处理和密码学等领域还是至关重要的。
在 Go 语言中支持以下几种操作位的方式:
```
& 位与
| 位或
^ 异或
&^ 位与非
<<左移
>> 右移
```
接下来我们会对每一个操作符进行详细的讨论并给出一些可以应用位操作的实例。
## `&` 操作符
在 Go 中,`&` 操作符用来在两个整数之间进行位 AND 运算。AND 操作有以下特性:
```
Given operands a, b
AND(a, b) = 1; only if a = b = 1
else = 0
// 给定 2 个操作数 a,b:
// 当且仅当 a 和 b 都为 1 时,操作 AND(a, b) 的结果为 1。
// 否则操作 AND(a, b) 为 0。
```
AND 操作符是一个很好的将整数的指定位清零的方式。在下面的例子中,我们使用 `&` 运算符将数字后 4 位清零。
```go
func main() {
var x uint8 = 0xAC // x = 10101100
x = x & 0xF0 // x = 10100000
}
```
所有的二进制操作符都支持简写形式,我们可以把上面的例子改为简写形式:
```go
func main() {
var x uint8 = 0xAC // x = 10101100
x &= 0xF0 // x = 10100000
}
```
另外一个小技巧就是可以通过 `&` 来判断一个数字是奇数还是偶数。我们可以将数字和值 1 使用 `&` 做 AND 运算。如果结果是 1,那说明原来的数字是一个奇数。
```go
import (
"fmt"
"math/rand"
)
func main() {
for x := 0; x <100; x {
num := rand.Int()
if num&1 == 1 {
fmt.Printf("%d is odd\n", num)
} else {
fmt.Printf("%d is even\n", num)
}
}
}
```
[在线运行](https://play.golang.org/p/2mTNOtioNM)
## `|` 操作符
`|` 用来做数字的位 OR 运算。OR 操作符有以下特性:
```
Given operands a, b
OR(a, b) = 1; when a = 1 or b = 1
else = 0
// 给定两个操作数 a,b
// 当且仅当 a 和 b 均为 0 时,操作 OR(a, b) 返回 0。
// 否者返回 1。
```
我们可以使用这个特性来将一个整数中的指定位置为 1。在下面的例子里,我们使用 OR 运算将第 3、7、8 位置为 1。
```go
func main() {
var a uint8 = 0
a |= 196
fmt.Printf("%b", a)
}
// prints 11000100
^^ ^
```
[在线运行](https://play.golang.org/p/3VPv4D83Oj)
当对一个数字使用掩码技术,OR 是非常有用的。下面的例子我们可以设置更多的位:
```go
func main() {
var a uint8 = 0
a |= 196
a |= 3
fmt.Printf("%b", a)
}
// prints 11000111
```
[在线运行](https://play.golang.org/p/7aJLwh3y4x)
在上面的例子中,我们不仅有数字 196 中的所有位,而且最后的两位也被数字 3 置 1。我们可以一直进行置 1 操作,直到所有的位都为 1。
### 使用位作为配置信息
现在,回顾 `AND(a,1) = a if and only if a = 1`。我们可以使用这个技巧来查询指定位上的值。例如 `a & 196` 将会返回 `196`,因为在 `a` 中 `196` 的所有位都被置 1 了。所以我们能够使用 OR 和 AND 来设置和读取配置信息的值。
下面的代码完成了这个功能。函数 `procstr` 转换给定的字符串。它接收两个参数:第一个参数 `str` 是一个要被转换的字符串,第二个参数 `conf` 使用掩码指定转换时的配置信息。
```go
const (
UPPER = 1 // upper case
LOWER = 2 // lower case
CAP = 4 // capitalizes
REV = 8 // reverses
)
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
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
}
```
[在线运行](https://play.golang.org/p/4E05PQwj5q)
调用 `procstr("HELLO PEOPLE!", LOWER|REV|CAP)` 将会把字符串转换成小写,反转并将每个单词的首字母转换成大写。当 `conf` 上的第 2、3、4 位为 1 时(conf 等于 14)将会执行上述操作。在内部我们使用 if 语句来取出这些位并且根据相应的配置操作字符串。
## `^` 操作符
XOR 操作符在 Go 中用 `^` 表示。XOR 是特例化的 OR,它有以下特性:
```go
Given operands a, b
XOR(a, b) = 1; only if a != b
else = 0
// 给定 2 个操作数 a,b
// 当且仅当 a!=b 时,操作 XOR(a, b) 返回 1。
// 否者返回 0。
```
这就暗示了我们可以使用 XOR 来切换指定位上的值。例如,给定一个 16 位的值,我们可以使用下面的代码来切换它的前八位:
```go
func main() {
var a uint16 = 0xCEFF
a ^= 0xFF00 // same a = a ^ 0xFF00
}
// a = 0xCEFF (11001110 11111111)
// a ^=0xFF00 (00110001 11111111)
```
在之前的代码中,位的值通过 XOR 操作在 0 和 1 之间切换。XOR 的一个实际的用途就是比较两个数字正负号是否相同。两个数字 `a`、`b`,如果 `(a ^ b) >= 0` 那么 a 和 b 同号,如果 `(a ^ b) <0` 那么 a 和 b 异号。
```go
func main() {
a, b := -12, 25
fmt.Println("a and b have same sign?", (a ^ b) >= 0)
}
```
[在线运行](https://play.golang.org/p/6rAPti5bXJ)
当上述代码执行会输出 `a and b have same sign? false`。使用 Go Playground 可以修改不同的符号查看不同的结果。
### 使用 `^` 作为位非操作
不像其它语言(C/C 、Java、Python、Javascript 等),Go 没有一元运算符。XOR 操作符 `^` 可以作为一元操作符来计算一个数字的补码。给定一个位 `x`,在 Go 中 `^x = 1 ^ x` 将会反转 x 的位。我们可以通过 `^a` 来计算变量 `a` 的补码。
```go
func main() {
var a byte = 0x0F
fmt.Printf("b\n", a)
fmt.Printf("b\n", ^a)
}
// prints
00001111 // var a
11110000 // ^a
```
[在线运行](https://play.golang.org/p/5d1fQjDAIv)
### `&^` 运算符
`&^` 运算符叫做 AND NOT。它是一个 使用 `AND` 后,再使用 `NOT` 操作的简写。该操作符定义如下:
```
Given operands a,b
AND_NOT(a, b) = AND(a, NOT(b))
// 给定两个操作数 a,b
// 当 a=NOT(b)=1 时,操作 AND_NOT(a, b) 返回 1。
// 否则返回 0。
```
它有一个有意思的特性:如果第二个操作符返回 1。那么该位将会被清 0。
```
AND_NOT(a, 1) = 0; clears a
AND_NOT(a, 0) = a;
```
下面这个代码片段使用 AND NOT 操作符来清掉 `a` 的后 4 位(`1010 1011` 到 `1010 0000`)。
```go
func main() {
var a byte = 0xAB
fmt.Printf("b\n", a)
a &^= 0x0F
fmt.Printf("b\n", a)
}
// prints:
10101011
10100000
```
[在线运行](https://play.golang.org/p/UPUlBOPRGh)
## `<<` 和 `>>` 运算符
和其它 C 家族语言一样,Go 使用 `<<` 和 `>>` 来代表左移或者右移运算,定义如下:
```
Given integer operands a and n,
a <
a >> n; 将 a 中的所有位向右偏移 n 次
```
例如:在下面的片段中,`a` 使用左移运算符(`00000011`)左移 3 次。每次的结果都会被打印出来。
```go
func main() {
var a int8 = 3
fmt.Printf("b\n", a)
fmt.Printf("b\n", a<<1)
fmt.Printf("b\n", a<<2)
fmt.Printf("b\n", a<<3)
}
// prints:
00000011
00000110
00001100
00011000
```
需要注意的是,每次左移右边的位都会被 0 填充。相反的,使用右移运算符时左边的位都会被 0 填充(有符号数字除外,具体请看之后的 *Arithmetic Shifts* 章节)。
```go
func main() {
var a uint8 = 120
fmt.Printf("b\n", a)
fmt.Printf("b\n", a>>1)
fmt.Printf("b\n", a>>2)
}
// prints:
01111000
00111100
00011110
```
一些简单的左移和右移的使用技巧就是乘法和除法,其中每次的位移都是乘或者除 2 次幂。下面的代码将 200 除以 2。
```go
func main() {
a := 200
fmt.Printf("%d\n", a>>1)
}
// prints:
100
```
[在线运行](https://play.golang.org/p/EJi0YCARun)
或者将一个值乘 4:
```go
func main() {
a := 12
fmt.Printf("%d\n", a<<2)
}
// prints:
48
```
[在线运行](https://play.golang.org/p/xuJRcKgMVV)
位移运算符提供一种非常有趣的方式来设置一个二进制的值。我们使用 `|` 和 `<<` 来设置 `a` 第三位的值。
```go
func main() {
var a int8 = 8
fmt.Printf("b\n", a)
a = a | (1<<2)
fmt.Printf("b\n", a)
}
// prints:
00001000
00001100
```
[在线运行](https://play.golang.org/p/h7WoP7ieuI)
或者使用 `&` 和位移运算符来测试第 n 位是不是指定的值:
```go
func main() {
var a int8 = 12
if a&(1<<2) != 0 {
fmt.Println("take action")
}
}
// prints:
take action
```
[在线运行](https://play.golang.org/p/Ptc7Txk5Jb)
使用 `&^` 和位移运算来给第 n 位置 0:
```go
func main() {
var a int8 = 13
fmt.Printf("b\n", a)
a = a &^ (1 <<2)
fmt.Printf("b\n", a)
}
// prints:
1101
1001
```
[在线运行](https://play.golang.org/p/Stjq9oOjKz)
### 位移运算符注意事项
当移动的是一个有符号的值,Go 将会自动的适配位移运算。在向右位移时,正负位上的值将会填充在缺失的位上。
go
text
https
git
bit
cpu
编程
main
int
写下你的评论吧 !
吐个槽吧,看都看了
会员登录
|
用户注册
推荐阅读
go
2023年,Android开发前景如何?25岁还能转行吗?
近期,关于Android开发行业的讨论在多个平台上热度不减,许多人担忧其未来发展。本文将探讨当前Android开发市场的现状、薪资水平及职业选择建议。 ...
[详细]
蜡笔小新 2024-11-21 18:08:07
go
JUnit下的测试和suite
nsitionalENhttp:www.w3.orgTRxhtml1DTDxhtml1-transitional.dtd ...
[详细]
蜡笔小新 2024-11-21 16:03:49
split
Web动态服务器Python基本实现
Web动态服务器Python基本实现 ...
[详细]
蜡笔小新 2024-11-21 08:01:30
split
深入理解:AJAX学习指南
本文详细探讨了AJAX的基本概念、工作原理及其在现代Web开发中的应用,旨在为初学者提供全面的学习资料。 ...
[详细]
蜡笔小新 2024-11-20 17:58:54
main
深入理解Java SE 8新特性:Lambda表达式与函数式编程
本文作为‘Java SE 8新特性概览’系列的一部分,将详细探讨Lambda表达式。通过多种示例,我们将展示Lambda表达式的不同应用场景,并解释编译器如何处理这些表达式。 ...
[详细]
蜡笔小新 2024-11-20 14:19:27
jsp
Struts2 + json+ jquery 实现三级联动action和jsp代码竟然有小红叉,提示缺双引号,检查了转义符号也没缺啊,求解
publicclassBindActionextendsActionSupport{privateStringproString;privateStringcitString; ...
[详细]
蜡笔小新 2024-11-21 16:25:41
数组
Go从入门到精通系列视频之go编程语言密码学哈希算法(二)
Go从入门到精通系列视频之go编程语言密码学哈希算法(二) ...
[详细]
蜡笔小新 2024-11-21 10:55:36
数组
OBS Studio自动化实践:利用脚本批量生成录制场景
本文探讨了如何利用OBS Studio进行高效录屏,并通过脚本实现场景的自动生成。适合对自动化办公感兴趣的读者。 ...
[详细]
蜡笔小新 2024-11-21 10:44:53
main
web: _show -> _info 造轮子编程
问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ...
[详细]
蜡笔小新 2024-11-21 10:21:24
go
Python 领跑!2019年2月编程语言排名更新
根据最新的编程语言流行指数(PYPL)排行榜,Python 在2019年2月的份额达到了26.42%,稳坐榜首位置。 ...
[详细]
蜡笔小新 2024-11-21 09:18:39
install
设置Shadowsocks公共代理的关键步骤
本文详细介绍了如何正确设置Shadowsocks公共代理,包括调整超时设置、检查系统限制、防止滥用及遵守DMCA法规等关键步骤。 ...
[详细]
蜡笔小新 2024-11-20 20:41:33
hash
使用Service Locator模式实现高效的服务命名访问
本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ...
[详细]
蜡笔小新 2024-11-20 19:26:30
hash
解析与应用:org.apache.gobblin.metrics.GobblinMetrics.getName() 方法
本文详细探讨了 Java 中 org.apache.gobblin.metrics.GobblinMetrics 类下的 getName() 方法的使用场景及其代码实现,提供了多个实际应用示例以加深理解。 ...
[详细]
蜡笔小新 2024-11-20 13:26:36
sum
fleaframedb使用之JPA封装介绍
flea,frame,db,使用,之 ...
[详细]
蜡笔小新 2024-11-20 12:00:16
sum
软件测试行业深度解析:迈向高薪的必经之路
本文深入探讨了软件测试行业的发展现状及未来趋势,旨在帮助有志于在该领域取得高薪的技术人员明确职业方向和发展路径。 ...
[详细]
蜡笔小新 2024-11-21 17:32:44
多少年都不会变
这个家伙很懒,什么也没留下!
Tags | 热门标签
replace
jsp
sum
integer
copy
include
dll
frameworks
tree
substring
search
go
perl
main
audio
hashset
dagger
expression
hash
python2
bit
actionscrip
split
install
bash
bytecode
数组
cPlusPlus
triggers
php8
RankList | 热门文章
1
网课公众号搭建
2
最全的JAVA知识汇总(附讲解和思维导图)
3
博图静态变量static的作用
4
linux shell输入与输出
5
使用 .net MVC+Vue.js 实现 elsteps
6
jTemplates部分语法介绍
7
(转)VS自带工具:dumpbin的使用
8
linux时间字符串转正常时间
9
PostgreSQL 13 SQL 命令 GRANT
10
织梦DedeCMS配置手机wap站点,并绑定二级域名
11
css样式 boxshadow属性
12
2017亚马逊人工智能奖公布:他们的AI有什么不同?
13
flask+ajax post 400错误
14
翻译 | 编写SVG的口袋指南(上)
15
华为仿真软件eNSP路由器配置
PHP1.CN | 中国最专业的PHP中文社区 |
DevBox开发工具箱
|
json解析格式化
|
PHP资讯
|
PHP教程
|
数据库技术
|
服务器技术
|
前端开发技术
|
PHP框架
|
开发工具
|
在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved |
京公网安备 11010802041100号
|
京ICP备19059560号-4
| PHP1.CN 第一PHP社区 版权所有