【问题标题】:Swap two numbers golang交换两个数字 golang
【发布时间】:2016-02-29 18:49:16
【问题描述】:

我正在尝试了解 Go 的内部结构。考虑以下代码

a,b := 10,5
b,a = a,b

上面的代码完美地交换了 2 个数字,a 变为 5,b 变为 10。我无法理解这是如何工作的。考虑在第二行代码中,如果先将 a 分配给 b,那么 b 将是 10。现在如果我们将 b 分配给 a,那么 a 也不应该是 10。

请帮助我了解这是如何工作的

谢谢

【问题讨论】:

  • 编译器使用寄存器作为临时存储,就像临时变量一样
  • 把它变成可执行文件,然后反汇编
  • go tool compile -S file
  • 我有一个 .o 文件。有没有办法反汇编/反编译它
  • 这样一个简单的程序,根本就没有ab这两个变量。每个引用ab 的地方都是常量105。即使你在ab 上加/乘一些东西,比如a += 999b *= 999,或打印它们,例如 fmt.Println(a, b)。都是常数。如今,编译器已经足够聪明了。只有在某些复杂的情况下使用变量时才会在内存中创建变量,因为它们必须创建。即使到那时,由于定义和交换之间没有代码,ab 将直接设置为 510

标签: go


【解决方案1】:

TL;DR:反汇编表明 CPU 必须足够聪明才能看到正在发生的事情并使用寄存器来避免覆盖内存中的现有值。


这个问题帮助我了解了更多关于 Golang 的知识,非常感谢!

要弄清楚编译器是如何生成本机代码的,我们需要查看它生成的汇编代码,这些代码被链接器转换为机器代码。

我写了一个小 Go 程序来帮助解决这个问题:

package main

import "fmt"

func main() {
    fmt.Println(myfunction())
}

func myfunction() []int {
    a, b := 10, 5
    b, a = a, b
    return []int{a, b}
}

使用go tool compile -S > swap.s,然后我CTRL - F'd for myfunction(这是该名称的要点:易于搜索),并找到了这四行,它们对应于第一行Go 代码中的两行 myfunction:(注意这是针对我的 64 位机器的;输出在其他架构(如 32 位)上会有所不同)

0x0028 00040 (swap.go:10)   MOVQ    $10, CX         ; var a = 10
0x002f 00047 (swap.go:10)   MOVQ    $5, AX          ; var b = 5
0x0036 00054 (swap.go:11)   MOVQ    CX, "".b+16(SP) ; copy a to *b+16
0x003b 00059 (swap.go:11)   MOVQ    AX, "".a+24(SP) ; copy b to *a+24 

Go 的反汇编对调试非常有帮助:D

查看the Golang docs on asm,我们可以看到汇编器使用间接来处理值。

当程序运行时,CPU 足够聪明,可以看到正在发生的事情并使用寄存器来避免覆盖现有值。

Here's the full disassembly, if you're interested.

【讨论】:

  • C 也能做到这一点吗?与机器代码相比,Golang 具有高级抽象,能够指示 CPU 一次读取两个或多个值/变量。
  • 没有CPU是聪明的! CPU 没有提示不覆盖值,它会很乐意这样做。第一次写入将在 uop 生成期间被消除,或者将融合到宏 uop 中。除了 uarch 问题,这里发生的是编译器生成代码,以便将交换的值直接分配给返回元组。编译器可以这样做,因为交换是在函数内完成的。如果您在单独的函数中执行交换操作,您会看到编译器将使用一个额外的临时寄存器。
【解决方案2】:

这是我在 Go 中交换数字的实现:

func swap_int(a *int, b *int) {
   var x int
  
   x = *a
   *a = *b
   *b = x
}

func main() {
  var a int = 40
  var b int = 32
  fmt.Println("a = %d, b = %d\n", a, b)
  swap_int(&a, &b)
  fmt.Println("a = %d, b = %d", a, b)
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-05
    • 1970-01-01
    • 1970-01-01
    • 2022-07-13
    相关资源
    最近更新 更多