不久前有人问了一个问题,关于 Golang 实际上如何在像a, b = b, a.为了回答这个问题,我拿出了我的 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,我找到了这四行,它们对应myfunction于 Go 代码中的前两行:(注意这是针对我的 64 位机器;输出会在其他架构(如 32 位)上有所不同)0x0028 00040 (swap.go:10) MOVQ $10, CX ; var a = 100x002f 00047 (swap.go:10) MOVQ $5, AX ; var b = 50x0036 00054 (swap.go:11) MOVQ CX, "".b+16(SP) ; copy a to *b+160x003b 00059 (swap.go:11) MOVQ AX, "".a+24(SP) ; copy b to *a+24 查看关于 asm 的 Golang 文档,我们可以看到汇编程序使用间接来处理值。当程序运行时,CPU 足够聪明,可以看到发生了什么,并使用寄存器来避免覆盖现有值。这是完整的拆解,如果您有兴趣。根据我对(英特尔)x86 组装的微薄知识,我的 评论获得了 6 票,我的回答获得了接受和 3 票。Golang程序集的四行实际上是做什么的?我的回答正确吗?我问是因为我链接的文档不是很(根本)详尽。
2 回答
临摹微笑
TA贡献1982条经验 获得超2个赞
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
CX, AX, 和SP是寄存器。a和b分别是 SP+24 和 SP+16 处堆栈上的变量。
开满天机
TA贡献1786条经验 获得超13个赞
它将常量 10 和 5 加载到 CPU 寄存器中,然后将寄存器存储到为变量a和保留的堆栈位置b。
它相当于:
CX := 10
AX := 5
b := CX
a := AX
请注意,一个不错的优化编译器应该将其优化为将常量直接存储到堆栈位置的代码:
b := 10
a := 5
或者更好的是完全消除变量:
return []int{5, 10}
- 2 回答
- 0 关注
- 126 浏览
添加回答
举报
0/150
提交
取消