首页
技术博客
PHP教程
数据库技术
前端开发
HTML5
Nginx
php论坛
新用户注册
|
会员登录
PHP教程
技术博客
编程问答
PNG素材
编程语言
前端技术
Android
PHP教程
HTML5教程
数据库
Linux技术
Nginx技术
PHP安全
WebSerer
职场攻略
JavaScript
开放平台
业界资讯
大话程序猿
登录
极速注册
取消
热门标签 | HotTags
tags
vbscript
javascript
audio
cPlusPlus
post
frameworks
heatmap
loops
instance
lua
emoji
shell
timezone
command
window
list
数组
python3
bytecode
dagger
copy
process
php
uml
byte
controller
perl
jsp
import
stream
range
c语言
future
foreach
regex
random
php5
uri
heap
jar
ip
string
select
php7
ascii
dll
match
metadata
cmd
replace
split
default
format
bash
js
dockerfile
main
solr
search
httprequest
hash
cSharp
input
spring
subset
io
sum
iostream
scala
client
tree
vba
install
buffer
filter
actionscrip
erlang
java
当前位置:
开发笔记
>
编程语言
> 正文
深入解析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
写下你的评论吧 !
吐个槽吧,看都看了
会员登录
|
用户注册
推荐阅读
import
Akka BackoffSupervisor的深入解析与实践
本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ...
[详细]
蜡笔小新 2024-12-27 15:04:09
byte
优化ListView性能
本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ...
[详细]
蜡笔小新 2024-12-28 10:36:30
process
扫描线三巨头 hdu1928hdu 1255 hdu 1542 [POJ 1151]
学习链接:http:blog.csdn.netlwt36articledetails48908031学习扫描线主要学习的是一种扫描的思想,后期可以求解很 ...
[详细]
蜡笔小新 2024-12-26 20:04:36
import
golang常用库:配置文件解析库/管理工具viper使用
golang常用库:配置文件解析库管理工具-viper使用-一、viper简介viper配置管理解析库,是由大神SteveFrancia开发,他在google领导着golang的 ...
[详细]
蜡笔小新 2024-12-28 13:47:52
import
java编写的简易计算器
主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ...
[详细]
蜡笔小新 2024-12-27 18:18:10
数组
JQuery基础:省市联动与表单验证
本文介绍了如何使用JQuery实现省市二级联动和表单验证。首先,通过change事件监听用户选择的省份,并动态加载对应的城市列表。其次,详细讲解了使用Validation插件进行表单验证的方法,包括内置规则、自定义规则及实时验证功能。 ...
[详细]
蜡笔小新 2024-12-27 17:10:48
list
深入解析ExpandableComposite.addExpansionListener()方法及其应用
本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ...
[详细]
蜡笔小新 2024-12-27 16:11:49
controller
深入解析 MVC 源码:ParameterDescriptor 与 Action 方法参数绑定
在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ...
[详细]
蜡笔小新 2024-12-27 15:26:10
import
寻找满足特定条件的整数N的最大和(a+b)
本文探讨了如何在给定整数N的情况下,找到两个不同的整数a和b,使得它们的和最大,并且满足特定的数学条件。 ...
[详细]
蜡笔小新 2024-12-26 19:26:18
list
解析Java中Text.splitText()方法及其应用场景
本文详细介绍了Java中org.w3c.dom.Text类的splitText()方法,通过多个代码示例展示了其实际应用。该方法用于将文本节点在指定位置拆分为两个节点,并保持在文档树中。 ...
[详细]
蜡笔小新 2024-12-26 18:31:42
copy
编写有趣的VBScript恶作剧脚本
本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ...
[详细]
蜡笔小新 2024-12-28 09:46:23
controller
Handling Null Object Encoding in OAuth 1.0a API Implementation
Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ...
[详细]
蜡笔小新 2024-12-28 08:54:34
数组
C语言实现小写金额转换为大写金额
在金融和会计领域,准确无误地填写票据和结算凭证至关重要。这些文件不仅是支付结算和现金收付的重要依据,还直接关系到交易的安全性和准确性。本文介绍了一种使用C语言实现小写金额转换为大写金额的方法,确保数据的标准化和规范化。 ...
[详细]
蜡笔小新 2024-12-27 12:39:06
import
Android LED 数字字体的应用与实现
本文介绍了一种适用于 Android 应用的 LED 数字字体(digital font),并详细描述了其在 UI 设计中的应用场景及其实现方法。这种字体常用于视频、广告倒计时等场景,能够增强视觉效果。 ...
[详细]
蜡笔小新 2024-12-27 10:34:22
list
Unity 客户端框架设计:UI管理系统的构建
本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ...
[详细]
蜡笔小新 2024-12-27 10:28:40
多少年都不会变
这个家伙很懒,什么也没留下!
Tags | 热门标签
tags
vbscript
javascript
audio
cPlusPlus
post
frameworks
heatmap
loops
instance
lua
emoji
shell
timezone
command
window
list
数组
python3
bytecode
dagger
copy
process
php
uml
byte
controller
perl
jsp
import
RankList | 热门文章
1
(爬取菜单信息)想要一次性获取标签的所有的东西时不需要find_all再一个个循环,直接text即可!!!!
2
Z字形变换( ZigZag Conversion)java
3
Javaweb——Spring Boot 系列(16)认证与授权
4
『P2P僵尸网络深度追踪——Mozi』(一)Winter is coming!
5
BO : Proposition : IMPROVEMENT Admin Modules Positions
6
快照_快照图
7
maven update 自动修改dynamic web module_Angular 8.0 正式发布! 支持更多 Web 标准
8
php 360kan 抓取,米酷MKCMS自动采集360kan影视站6.2.6无授权版
9
深度学习:用生成对抗网络(GAN)来恢复高分辨率(高精度)图片 (附源码,模型与数据集)
10
李丽欣照片,李丽欣的瓜
11
Dokan[转]
12
回溯算法的简单使用
13
dpi shell命令 安卓_太酷了!这款开源安卓投屏软件,让你工作游戏两不误!
14
iOS简易图片选择器 (图片可多选,仿微信)
15
邀请暗恋的女同学去吃饭,可被拒绝,心理巨不爽!
PHP1.CN | 中国最专业的PHP中文社区 |
DevBox开发工具箱
|
json解析格式化
|
PHP资讯
|
PHP教程
|
数据库技术
|
服务器技术
|
前端开发技术
|
PHP框架
|
开发工具
|
在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved |
京公网安备 11010802041100号
|
京ICP备19059560号-4
| PHP1.CN 第一PHP社区 版权所有