一段时间以前,有人询问一个问题,关于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 ofmyfunction
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.
我的评论,基于我对(Intel) x86汇编的了解,获得了6票,我的答案得到了接受和3票。
Golang汇编的这四行代码实际上是在做什么?我的答案正确吗?
我问这个问题是因为我链接的文档不够详尽。
mov rcx,10 \ mov rax,5 \ mov [rsp+16],rcx \ mov [rsp+24],rax
(这在64位代码中几乎是合理的,但它浪费了无用的REX.W前缀在带有微小立即数的mov-immediates上)。 - harold