搜索
首页后端开发Golang一文详解Golang中的位操作

一文详解Golang中的位操作

Sep 21, 2022 am 11:09 AM
gogolang

本篇文章带大家深入了解下Golang中的位操作,介绍一下详述每个操作符以及它们如何使用的案例,希望对大家有所帮助!

一文详解Golang中的位操作

在计算机内存昂贵,处理能力有限的美好旧时光里,用比较黑客范的位运算方式去处理信息是首选方式(某些情况下只能如此)。时至今日,直接使用位运算仍然是很多计算领域中不可或缺的部分,例如底层系统编程,图形处理,密码学等。【相关推荐:Go视频教程

Go 编程语言支持以下按位运算符:

&   bitwise AND
 |   bitwise OR
 ^   bitwise XOR
&^   AND NOT
>   right shift

本文的余下部分详述了每个操作符以及它们如何使用的案例。

& 运算符

在 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 的时候,那他就是奇数。我们可以用一个数字和 1 进行 & 操作,然后在和 1 做 AND 运算,如果的到的结果是 1 ,那么这个原始的数字就是奇数

import (
    "fmt"
    "math/rand"
)
func main() {
    for x := 0; x <p>在  <a href="https://play.golang.org/p/2mTNOtioNM" target="_blank">Playground</a>  上运行上面的例子</p><h4>
<span class="header-link octicon octicon-link"></span><strong>| 操作符</strong>
</h4><p><code>|</code> 对其整型操作数执行按位<code>或</code>操作。回想一下<code>或</code>操作符具备以下性质:</p><pre class="brush:php;toolbar:false">Given operands a, b
OR(a, b) = 1; when a = 1 or b = 1
              else = 0

我们可以利用按位操作符为给定的整数有选择地设置单个位。例如,在如下示例中我们使用按位将示例数(从低位到高位(MSB))中的第 3 ,第 7 和第 8 位置为 1 。

func main() {
    var a uint8 = 0
    a |= 196
    fmt.Printf("%b", a)
}

// 打印结果  11000100
            ^^   ^

练习场中可运行范例。

在使用位掩码技术为给定的整型数字设置任意位时,运算非常有用。例如,我们可以扩展之前的程序为变量 a 存储的值设置更多的位。

func main() {
    var a uint8 = 0
    a |= 196
    a |= 3
    fmt.Printf("%b", a)
}

// 打印结果 11000111

练习场中可以运行范例。

在前面的程序里,不仅要按位设置十进制的 196,而且要设置低位上的十进制 3。我们还可以继续(上更多的值)设置完所有的位。

位运算的配置用法

现在,回顾一下 AND(a, 1) = a 当且仅当 a = 1。 我们可以利用这个特性去查询其设置位的值。例如,在上述代码中 a & 196 会返回 196 是因为这几位的值在 a 中确实都存在。所以我们可以结合使用 OR 和  AND 运算的方式来分别设置和读取某位的配置值。.

接下来的源码片段演示了这个操作。函数 procstr 会转换字符串的内容。它需要两个参数:第一个, 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 {
    // 反转字符串
    rev := func(s string) string {
        runes := []rune(s)
        n := len(runes)
        for i := 0; i <p>在 Playground上面运行代码.</p><p>上面的 <code>procstr("HELLO PEOPLE!", LOWER|REV|CAP)</code> 方法会把字符串变成小写,然后反转字符串,最后把字符串里面的单词首字母变成大写。这个功能是通过设置 <code>conf</code> 里的第二,三,四位的值为 14 来完成的。然后代码使用连续的 if 语句块来获取这些位操作进行对应的字符串转换。</p><h4>
<span class="header-link octicon octicon-link"></span><strong>^ 操作符</strong>
</h4><p>在 Go 中  按位 <code>异或</code> 操作是用 <code>^</code> 来表示的。 <code>异或</code>运算符有如下的特点:</p><pre class="brush:php;toolbar:false">Given operands a, b
XOR(a, b) = 1; only if a != b
     else = 0

异或运算的这个特性可以用来把二进制位的一个值变成另外一个值。举个例子,给到一个 16 进制的值,我们可以使用以下代码切换前8位(从 MSB 开始)的值。

func main() {
    var a uint16 = 0xCEFF
    a ^= 0xFF00 // same a = a ^ 0xFF00
}

// a = 0xCEFF   (11001110 11111111)
// a ^=0xFF00   (00110001 11111111)

在前面的代码片段中,与 1 进行异或的位被翻转(从 0 到 1 或从 1 到  0)。异或 运算的一个实际用途,例如,可以利用 异或运算去比较两个数字的符号是否一样。当 (a ^ b) ≥ 0 (或相反符号的 (a ^ b) )为 <code>true 的时候,两个整数 a,b 具有相同的符号,如下面的程序所示:

func main() {
    a, b := -12, 25
    fmt.Println(&amp;amp;amp;quot;a and b have same sign?&amp;amp;amp;quot;, (a ^ b) &amp;amp;amp;gt;= 0)
}

在 Go 的 Playground运行代码。

当执行上面这个程序的时候,将会打印出:a and b have same sign? false。在 Go Playground 上修改程序里 a ,b 的符号,以便看到不同的结果。

^ 作为取反位运算符 (非)

不像其他语言 (c/c++,Java,Python,Javascript,等), Go 没有专门的一元取反位运算符。取而代之的是,XOR 运算符 ^,也可作为一元取反运算符作用于一个数字。对于给定位 x,在 Go 中 x = 1 ^ x 可以翻转该位。在以下的代码段中我们可以看到使用 ^a 获取变量 a 的取反值的操作。

func main() {
    var a byte = 0x0F
    fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a)
    fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, ^a)
}

// 打印结果
00001111     // var a
11110000     // ^a

练习场中可以运行范例。

&amp;amp;amp;^ 操作符

&amp;amp;amp;^ 操作符意为 与非,是 操作符的简写形式,它们定义如下。

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 操作符,将变量值1010 1011变为 1010 0000,清除了操作数上的低四位。

func main() {
    var a byte = 0xAB
     fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a)
     a &amp;amp;amp;amp;^= 0x0F
     fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a)
}

// 打印:
10101011
10100000

练习场中运行范例。

> 操作符

与其他 C 的衍生语言类似, Go 使用 和 <code>>> 来表示左移运算符和右移运算符,如下所示:

Given integer operands a and n,
a &amp;amp;amp;gt; n; shifts all bits in a to the right n times

例如,在下面的代码片段中变量 a00000011)的值将会左移位运算符分别移动三次。每次输出结果都是为了说明左移的目的。

func main() {
    var a int8 = 3
    fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a)
    fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a&amp;amp;amp;lt;p&amp;amp;amp;gt;在 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://play.golang.org/p/_lhE8OoZxY&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;Playground&amp;amp;amp;lt;/a&amp;amp;amp;gt; 运行代码&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;注意每次移动都会将低位右侧补零。相对应,使用右移位操作符进行运算时,每个位均向右方移动,空出的高位补零,如下示例 (有符号数除外,参考下面的算术移位注释)。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;pre class=&amp;amp;amp;quot;brush:php;toolbar:false&amp;amp;amp;quot;&amp;amp;amp;gt;func main() {
 var a uint8 = 120
 fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a)
 fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a&amp;amp;amp;gt;&amp;amp;amp;gt;1)
 fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a&amp;amp;amp;gt;&amp;amp;amp;gt;2)
}

// 打印:
01111000
00111100
00011110

练习场中可以运行范例。

可以利用左移和右移运算中,每次移动都表示一个数的 2 次幂这个特性,来作为某些乘法和除法运算的小技巧。例如,如下代码中,我们可以使用右移运算将 200(存储在变量 a 中)除以 2 。

func main() {
    a := 200
    fmt.Printf(&amp;amp;amp;quot;%d\n&amp;amp;amp;quot;, a&amp;amp;amp;gt;&amp;amp;amp;gt;1)
}

// 打印:
100

练习场 中可以运行范例。

或是通过左移 2 位,将一个数乘以4:

func main() {
    a := 12
    fmt.Printf(&amp;amp;amp;quot;%d\n&amp;amp;amp;quot;, a&amp;amp;amp;lt;p&amp;amp;amp;gt;在 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://play.golang.org/p/xuJRcKgMVV&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;练习场&amp;amp;amp;lt;/a&amp;amp;amp;gt; 中可以运行范例。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;位移运算符提供了有趣的方式处理二进制值中特定位置的值。例如,下列的代码中,&amp;amp;amp;lt;code&amp;amp;amp;gt;|&amp;amp;amp;lt;/code&amp;amp;amp;gt; 和 &amp;amp;amp;lt;code&amp;amp;amp;gt; 用于设置变量 &amp;amp;amp;lt;code&amp;amp;amp;gt;a&amp;amp;amp;lt;/code&amp;amp;amp;gt; 的第三个 bit 位。&amp;amp;amp;lt;/code&amp;amp;amp;gt;&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;pre class=&amp;amp;amp;quot;brush:php;toolbar:false&amp;amp;amp;quot;&amp;amp;amp;gt;func main() {
    var a int8 = 8
    fmt.Printf(&amp;amp;amp;quot;%08b\n&amp;amp;amp;quot;, a)
    a = a | (1&amp;amp;amp;lt;p&amp;amp;amp;gt;可以在 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://play.golang.org/p/h7WoP7ieuI&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;练习场&amp;amp;amp;lt;/a&amp;amp;amp;gt; 中运行代码示例。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;或者,您可以组合位移运算符和 &amp;amp;amp;lt;code&amp;amp;amp;gt;&amp;amp;amp;amp;&amp;amp;amp;lt;/code&amp;amp;amp;gt; 测试是否设置了第n位,如下面示例所示:&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;pre class=&amp;amp;amp;quot;brush:php;toolbar:false&amp;amp;amp;quot;&amp;amp;amp;gt;func main() {
    var a int8 = 12
    if a&amp;amp;amp;amp;(1&amp;amp;amp;lt;p&amp;amp;amp;gt;在 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://play.golang.org/p/Ptc7Txk5Jb&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;练习场&amp;amp;amp;lt;/a&amp;amp;amp;gt;中运行代码。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;使用  &amp;amp;amp;lt;code&amp;amp;amp;gt;&amp;amp;amp;amp;^&amp;amp;amp;lt;/code&amp;amp;amp;gt; 和位移运算符,我们可以取消设置一个值的某个位。例如,下面的示例将变量 a 的第三位置为 0 :&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;pre class=&amp;amp;amp;quot;brush:php;toolbar:false&amp;amp;amp;quot;&amp;amp;amp;gt;func main() {
    var a int8 = 13 
    fmt.Printf(&amp;amp;amp;quot;%04b\n&amp;amp;amp;quot;, a)
    a = a &amp;amp;amp;amp;^ (1 &amp;amp;amp;lt;p&amp;amp;amp;gt;在 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://play.golang.org/p/Stjq9oOjKz&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;练习场&amp;amp;amp;lt;/a&amp;amp;amp;gt; 中运行代码。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;h4&amp;amp;amp;gt;
&amp;amp;amp;lt;span class=&amp;amp;amp;quot;header-link octicon octicon-link&amp;amp;amp;quot;&amp;amp;amp;gt;&amp;amp;amp;lt;/span&amp;amp;amp;gt;&amp;amp;amp;lt;strong&amp;amp;amp;gt;关于算术位移运算的笔记&amp;amp;amp;lt;/strong&amp;amp;amp;gt;
&amp;amp;amp;lt;/h4&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;当要位移的值(左操作数)是有符号值时,Go 自动应用算术位移。在右移操作期间,复制(或扩展)二进制补码符号位以填充位移的空隙。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;h4&amp;amp;amp;gt;
&amp;amp;amp;lt;span class=&amp;amp;amp;quot;header-link octicon octicon-link&amp;amp;amp;quot;&amp;amp;amp;gt;&amp;amp;amp;lt;/span&amp;amp;amp;gt;&amp;amp;amp;lt;strong&amp;amp;amp;gt;总结&amp;amp;amp;lt;/strong&amp;amp;amp;gt;
&amp;amp;amp;lt;/h4&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;与其它现代运算符一样,Go 支持所有二进制位操作运算符。这篇文章仅仅提供了可以用这些操作符完成的各种黑科技示例。你可以在网络上找到很多文章,特别是 Sean Eron Anderson 写的 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://graphics.stanford.edu/~seander/bithacks.html&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;Bit Twiddling Hacks&amp;amp;amp;lt;/a&amp;amp;amp;gt; 。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;关注 Vladim &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://twitter.com/VladimirVivien&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;@vladimirvivien&amp;amp;amp;lt;/a&amp;amp;amp;gt; 的 Twitter。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;如果你正在学习 Go,阅读  Vladimir Vivien 关于 Go 的书,名为 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://www.packtpub.com/application-development/learning-go-programming&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;Learning Go Programming&amp;amp;amp;lt;/a&amp;amp;amp;gt; 。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;这篇文章开始由作者 Vladimir Vivien 发布在 Medium 上,名为 &amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://medium.com/learning-the-go-programming-language/bit-hacking-with-go-e0acee258827#.2hof13ia5&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot;&amp;amp;amp;gt;Bit Hacking with Go&amp;amp;amp;lt;/a&amp;amp;amp;gt;。&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;blockquote&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;英文原文地址:https://dev.to/vladimirvivien/bit-hacking-with-go&amp;amp;amp;lt;/p&amp;amp;amp;gt;&amp;amp;amp;lt;/blockquote&amp;amp;amp;gt;&amp;amp;amp;lt;p&amp;amp;amp;gt;更多编程相关知识,请访问:&amp;amp;amp;lt;a href=&amp;amp;amp;quot;https://www.php.cn/course.html&amp;amp;amp;quot; target=&amp;amp;amp;quot;_blank&amp;amp;amp;quot; textvalue=&amp;amp;amp;quot;编程视频&amp;amp;amp;quot;&amp;amp;amp;gt;编程视频&amp;amp;amp;lt;/a&amp;amp;amp;gt;!!&amp;amp;amp;lt;/p&amp;amp;amp;gt;

以上是一文详解Golang中的位操作的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:learnku。如有侵权,请联系admin@php.cn删除
您如何使用'反映”包裹检查GO中变量的类型和值?您如何使用'反映”包裹检查GO中变量的类型和值?Apr 30, 2025 pm 02:29 PM

文章讨论了使用GO的“反射”软件包进行可变检查和修改,突出显示方法和性能注意事项。

您如何使用'同步/原子”在Go中执行原子操作的软件包?您如何使用'同步/原子”在Go中执行原子操作的软件包?Apr 30, 2025 pm 02:26 PM

文章讨论了使用GO的“同步/原子”软件包进行并发编程中的原子操作,详细说明了其益处,例如防止比赛条件和提高性能。

在GO中创建和使用类型转换的语法是什么?在GO中创建和使用类型转换的语法是什么?Apr 30, 2025 pm 02:25 PM

本文讨论了GO中的类型转换,包括语法,安全转换实践,常见的陷阱和学习资源。它强调明确的类型转换和错误处理。[159个字符]

在GO中创建和使用类型断言的语法是什么?在GO中创建和使用类型断言的语法是什么?Apr 30, 2025 pm 02:24 PM

本文讨论了GO中的类型断言,重点是语法,诸如恐慌和不正确类型之类的潜在错误,安全的处理方法以及绩效影响。

您如何使用'选择”在Go中?您如何使用'选择”在Go中?Apr 30, 2025 pm 02:23 PM

本文解释了在GO中使用“选择”语句来处理多个频道操作的使用,其与“开关”语句的差异以及常见用例,例如处理多个渠道,实现超时,非B

在GO中创建和使用函数的语法是什么?在GO中创建和使用函数的语法是什么?Apr 30, 2025 pm 02:22 PM

本文讨论了《 GO》中的函数文字,详细介绍了它们的语法,用法作为论点以及诸如简洁的代码和封闭之类的好处。它还解释了函数文字中的变量范围。(159个字符)

您如何在GO中创建和使用函数关闭?您如何在GO中创建和使用函数关闭?Apr 30, 2025 pm 02:21 PM

本文解释了如何在GO中创建和使用功能封闭,突出了它们的好处,例如封装和状态管理,并讨论了避免的常见陷阱。

您如何将结构嵌入GO?您如何将结构嵌入GO?Apr 30, 2025 pm 02:20 PM

本文解释了GO中的结构嵌入,这是一种创建新结构的方法,其中包含用于代码重复使用和简化语法的其他结构。它讨论了诸如代码可重复性和类似继承的行为之类的好处,并详细介绍了如何访问嵌入

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

SublimeText3 Linux新版

SublimeText3 Linux新版

SublimeText3 Linux最新版

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境