这是Golang执行多重赋值的方式吗?

3

一段时间以前,有人询问一个问题,关于Golang如何在语句中交换变量,例如a,b = b,a

为了回答这个问题,我拿出了我的Golang编译器,戴上了思考帽子,然后给出了一个答案。SO(Stack Overflow)的问题应该是自包含的,所以这里是我缩短过的答案:

To figure out how the compiler makes native code, we need to look at the assembly code it generates, which is turned into machine code by the linker.

I wrote a little Go program to help with this:

package main     
import "fmt"

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

Using go tool compile -S > swap.s, I found these four lines, which correspond to the first two lines of myfunction in the Go code: (note this is for my 64-bit machine; the output will differ on other architechtures like 32-bit)

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 

Looking at the Golang docs on asm, we can see the assembler uses indirection to juggle the values.

When the program runs, the CPU is smart enough to see what's happening and use a register to avoid overwriting the existing value.

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

我的评论,基于我对(Intel) x86汇编的了解,获得了6票,我的答案得到了接受和3票。

Golang汇编的这四行代码实际上是在做什么?我的答案正确吗?

我问这个问题是因为我链接的文档不够详尽。


1
我不确定那个奇怪的语法是什么意思,但在反汇编后变成了mov rcx,10 \ mov rax,5 \ mov [rsp+16],rcx \ mov [rsp+24],rax(这在64位代码中几乎是合理的,但它浪费了无用的REX.W前缀在带有微小立即数的mov-immediates上)。 - harold
1
@harold 这是 Go 汇编语言,不是 x86。 - cat
2个回答

3

它正在将常量10和5加载到CPU寄存器中,然后将寄存器存储到为变量ab保留的堆栈位置中。

这相当于:

 CX := 10
 AX := 5
 b := CX
 a := AX

请注意,优秀的优化编译器应该将这个代码优化成直接将常量存储到堆栈位置的代码。
 b := 10
 a := 5

更好的做法是完全消除变量:
 return []int{5, 10}

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

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

CXAXSP都是寄存器。在栈上,变量ab分别位于SP+24和SP+16。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接