php小编草莓为您介绍一种在golang中与汇编代码一起工作的方法——For-Range。For-Range是golang中的一个循环结构,可以与汇编代码结合使用,提供更高效的性能和灵活性。通过使用For-Range,您可以在golang中轻松处理大量的数据,并且可以借助汇编代码的优势,提升程序的执行效率。在本文中,我们将详细介绍For-Range的使用方法,并讲解如何与汇编代码进行协作,以实现更高效的程序运行。
问题内容
当源代码被汇编时,我对 golang 中 for-range 内的指针用法感到困惑。例如,我们知道下面的变量value将始终位于相同的内存地址中,并且相应的汇编代码显示了相同的逻辑。
// Source Code func main() { a := []int{1, 3, 5} for _, value := range a { foo(&value) } } func foo(a *int) int { b := *a * 42 fmt.Println(b) return b } // Assembly Code "".main STEXT size=126 args=0x0 locals=0x38 funcid=0x0 0x0000 00000 (main.go:15) TEXT "".main(SB), ABIInternal, $56-0 0x0000 00000 (main.go:15) CMPQ SP, 16(R14) 0x0004 00004 (main.go:15) PCDATA $0, $-2 0x0004 00004 (main.go:15) JLS 119 0x0006 00006 (main.go:15) PCDATA $0, $-1 0x0006 00006 (main.go:15) SUBQ $56, SP 0x000a 00010 (main.go:15) MOVQ BP, 48(SP) 0x000f 00015 (main.go:15) LEAQ 48(SP), BP 0x0014 00020 (main.go:15) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0014 00020 (main.go:15) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0014 00020 (main.go:16) MOVQ $0, ""..autotmp_4+24(SP) 0x001d 00029 (main.go:16) LEAQ ""..autotmp_4+32(SP), CX 0x0022 00034 (main.go:16) MOVUPS X15, (CX) 0x0026 00038 (main.go:16) MOVQ $1, ""..autotmp_4+24(SP) 0x002f 00047 (main.go:16) MOVQ $3, ""..autotmp_4+32(SP) 0x0038 00056 (main.go:16) MOVQ $5, ""..autotmp_4+40(SP) 0x0041 00065 (main.go:16) XORL AX, AX 0x0043 00067 (main.go:18) JMP 103 0x0045 00069 (main.go:18) MOVQ AX, ""..autotmp_10+16(SP) 0x004a 00074 (main.go:18) MOVQ ""..autotmp_4+24(SP)(AX\*8), CX 0x004f 00079 (main.go:18) MOVQ CX, "".value+8(SP) 0x0054 00084 (main.go:19) LEAQ "".value+8(SP), AX // Here we see we always use "".value+8(SP) as the argument into foo() 0x0059 00089 (main.go:19) PCDATA $1, $0 0x0059 00089 (main.go:19) CALL "".foo(SB) 0x005e 00094 (main.go:18) MOVQ ""..autotmp_10+16(SP), CX 0x0063 00099 (main.go:18) LEAQ 1(CX), AX 0x0067 00103 (main.go:18) CMPQ AX, $3 0x006b 00107 (main.go:18) JLT 69 0x006d 00109 (main.go:21) PCDATA $1, $-1 0x006d 00109 (main.go:21) MOVQ 48(SP), BP 0x0072 00114 (main.go:21) ADDQ $56, SP 0x0076 00118 (main.go:21) RET 0x0077 00119 (main.go:21) NOP 0x0077 00119 (main.go:15) PCDATA $1, $-1 0x0077 00119 (main.go:15) PCDATA $0, $-2 0x0077 00119 (main.go:15) CALL runtime.morestack_noctxt(SB) 0x007c 00124 (main.go:15) PCDATA $0, $-1 0x007c 00124 (main.go:15) JMP 0 0x0000 49 3b 66 10 76 71 48 83 ec 38 48 89 6c 24 30 48 I;f.vqH..8H.l$0H 0x0010 8d 6c 24 30 48 c7 44 24 18 00 00 00 00 48 8d 4c .l$0H.D$.....H.L 0x0020 24 20 44 0f 11 39 48 c7 44 24 18 01 00 00 00 48 $ D..9H.D$.....H 0x0030 c7 44 24 20 03 00 00 00 48 c7 44 24 28 05 00 00 .D$ ....H.D$(... 0x0040 00 31 c0 eb 22 48 89 44 24 10 48 8b 4c c4 18 48 .1.."H.D$.H.L..H 0x0050 89 4c 24 08 48 8d 44 24 08 e8 00 00 00 00 48 8b .L$.H.D$......H. 0x0060 4c 24 10 48 8d 41 01 48 83 f8 03 7c d8 48 8b 6c L$.H.A.H...|.H.l 0x0070 24 30 48 83 c4 38 c3 e8 00 00 00 00 eb 82 $0H..8........ rel 90+4 t=7 "".foo+0 rel 120+4 t=7 runtime.morestack_noctxt+0
但是,当我更改源代码并尝试查看汇编代码中的变化时,我发现没有任何变化。
// Changed Source Code func main() { a := []int{1, 3, 5} for _, value := range a { v := value foo(&v) } } func foo(a *int) int { b := *a * 42 fmt.Println(b) return b } // Changed Assembly Code "".main STEXT size=126 args=0x0 locals=0x38 funcid=0x0 0x0000 00000 (main.go:15) TEXT "".main(SB), ABIInternal, $56-0 0x0000 00000 (main.go:15) CMPQ SP, 16(R14) 0x0004 00004 (main.go:15) PCDATA $0, $-2 0x0004 00004 (main.go:15) JLS 119 0x0006 00006 (main.go:15) PCDATA $0, $-1 0x0006 00006 (main.go:15) SUBQ $56, SP 0x000a 00010 (main.go:15) MOVQ BP, 48(SP) 0x000f 00015 (main.go:15) LEAQ 48(SP), BP 0x0014 00020 (main.go:15) FUNCDATA $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0014 00020 (main.go:15) FUNCDATA $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB) 0x0014 00020 (main.go:16) MOVQ $0, ""..autotmp_5+24(SP) 0x001d 00029 (main.go:16) LEAQ ""..autotmp_5+32(SP), CX 0x0022 00034 (main.go:16) MOVUPS X15, (CX) 0x0026 00038 (main.go:16) MOVQ $1, ""..autotmp_5+24(SP) 0x002f 00047 (main.go:16) MOVQ $3, ""..autotmp_5+32(SP) 0x0038 00056 (main.go:16) MOVQ $5, ""..autotmp_5+40(SP) 0x0041 00065 (main.go:16) XORL AX, AX 0x0043 00067 (main.go:18) JMP 103 0x0045 00069 (main.go:18) MOVQ AX, ""..autotmp_11+16(SP) 0x004a 00074 (main.go:18) MOVQ ""..autotmp_5+24(SP)(AX\*8), CX 0x004f 00079 (main.go:19) MOVQ CX, "".v+8(SP) 0x0054 00084 (main.go:20) LEAQ "".v+8(SP), AX // Here we see the logic of argument is the same as above. This makes me confused. 0x0059 00089 (main.go:20) PCDATA $1, $0 0x0059 00089 (main.go:20) CALL "".foo(SB) 0x005e 00094 (main.go:18) MOVQ ""..autotmp_11+16(SP), CX 0x0063 00099 (main.go:18) LEAQ 1(CX), AX 0x0067 00103 (main.go:18) CMPQ AX, $3 0x006b 00107 (main.go:18) JLT 69 0x006d 00109 (main.go:22) PCDATA $1, $-1 0x006d 00109 (main.go:22) MOVQ 48(SP), BP 0x0072 00114 (main.go:22) ADDQ $56, SP 0x0076 00118 (main.go:22) RET 0x0077 00119 (main.go:22) NOP 0x0077 00119 (main.go:15) PCDATA $1, $-1 0x0077 00119 (main.go:15) PCDATA $0, $-2 0x0077 00119 (main.go:15) CALL runtime.morestack_noctxt(SB) 0x007c 00124 (main.go:15) PCDATA $0, $-1 0x007c 00124 (main.go:15) JMP 0 0x0000 49 3b 66 10 76 71 48 83 ec 38 48 89 6c 24 30 48 I;f.vqH..8H.l$0H 0x0010 8d 6c 24 30 48 c7 44 24 18 00 00 00 00 48 8d 4c .l$0H.D$.....H.L 0x0020 24 20 44 0f 11 39 48 c7 44 24 18 01 00 00 00 48 $ D..9H.D$.....H 0x0030 c7 44 24 20 03 00 00 00 48 c7 44 24 28 05 00 00 .D$ ....H.D$(... 0x0040 00 31 c0 eb 22 48 89 44 24 10 48 8b 4c c4 18 48 .1.."H.D$.H.L..H 0x0050 89 4c 24 08 48 8d 44 24 08 e8 00 00 00 00 48 8b .L$.H.D$......H. 0x0060 4c 24 10 48 8d 41 01 48 83 f8 03 7c d8 48 8b 6c L$.H.A.H...|.H.l 0x0070 24 30 48 83 c4 38 c3 e8 00 00 00 00 eb 82 $0H..8........ rel 90+4 t=7 "".foo+0 rel 120+4 t=7 runtime.morestack_noctxt+0
那么局部变量 v
如何影响 for-range 呢?
正如上面的细节,我认为汇编代码应该显示新的局部变量的引入是如何工作的,但事实并非如此。
解决方法
几点。
规范仅针对您的情况说明了以下内容:
这就是全部:它说将会有变量,并且它们将会 重新使用。后一点意味着,比如说,如果您创建一个闭包(使用函数文字的匿名函数),它将关闭一个或多个迭代变量,并将其返回/保存在某处并在循环结束后调用或者与循环同时(例如,在一个单独的 goroutine 中),该闭包将在循环的每次迭代更新(或正在更新)时访问这些完全相同的变量。
如果您不做任何此类奇特的事情 - 例如,仅从循环体代码中的那些变量中读取,那么这些变量被重用的事实是无关紧要的。
让我们重申一下:规范没有对迭代变量的内存地址提供任何保证。
为什么这很重要?因为编译器可以自由地生成它希望的任何代码,只要结果以遵循规范的方式工作,并且编译器的作用至少取决于以下内容:
-
目标硬件(
GOARCH
)。 -
Go 的版本和 make(实现)。不要低估这一点:例如,规范并没有精确定义 GC 的工作方式,因此任何品牌和任何版本的 Go 都可以自由地实现移动 GC,这将移动内存中的任意变量并更新指向的所有指针他们。
目前,流行的 Go 版本(您应该使用的版本和 GCC 前端)并没有这样做,但没有什么可以阻止它们或任何其他实现这样做。
因此,最后,您会问为什么特定的编译器会生成看起来特别的代码,并且既不说明 Go 的品牌,也不说明其版本,也不说明您的 GOARCH
(尽管可以猜测它可能是 amd64
) 。因此,您的问题实际上是无法回答的,并且精确的答案不会太有用,因为它们很快就会过时。
因此,此类问题与 SO 无关。
我决定将所有这些作为答案,只是因为对于评论来说太多了。
在您的特定情况下,编译器可能分析了 foo
的代码,并发现它不会更新通过指针参数传递给它的变量,并且更重要的是不会将其进一步传递到调用堆栈。由于循环体中的 v
没有做任何其他事情,编译器可能会认为语义 v
可以被视为 variable
的纯粹别名,并且它只是跳过了该单独变量的创建。我可以想象,如果您将这些变量的指针传递给 foo
,并且让它打印这些地址,编译器将被迫实现 v
。
请注意,“关于”只是一个猜测。如果您想了解所有细节,您可以随时研究编译器的工作原理(Go 的两种流行实现都是 F/OSS 的一部分)和/或检测其代码。
另请注意,您可以要求编译器告诉您有关其功能的更多信息。最常用的 Go 实现(最初称为 gc
)在其 go build
和 go install
调用中支持 -gcflags
命令行参数,该调用将参数传递给编译器(请参阅 go 工具编译 -help
)。特别是,它的 -m
和 -N
(还有 -S
和 -live
)标志可能值得玩一下。
以上是For-Range 如何在 golang 中与汇编代码一起工作?的详细内容。更多信息请关注PHP中文网其他相关文章!

Golangisidealforbuildingscalablesystemsduetoitsefficiencyandconcurrency,whilePythonexcelsinquickscriptinganddataanalysisduetoitssimplicityandvastecosystem.Golang'sdesignencouragesclean,readablecodeanditsgoroutinesenableefficientconcurrentoperations,t

Golang在并发性上优于C ,而C 在原始速度上优于Golang。1)Golang通过goroutine和channel实现高效并发,适合处理大量并发任务。2)C 通过编译器优化和标准库,提供接近硬件的高性能,适合需要极致优化的应用。

选择Golang的原因包括:1)高并发性能,2)静态类型系统,3)垃圾回收机制,4)丰富的标准库和生态系统,这些特性使其成为开发高效、可靠软件的理想选择。

Golang适合快速开发和并发场景,C 适用于需要极致性能和低级控制的场景。1)Golang通过垃圾回收和并发机制提升性能,适合高并发Web服务开发。2)C 通过手动内存管理和编译器优化达到极致性能,适用于嵌入式系统开发。

Golang在编译时间和并发处理上表现更好,而C 在运行速度和内存管理上更具优势。1.Golang编译速度快,适合快速开发。2.C 运行速度快,适合性能关键应用。3.Golang并发处理简单高效,适用于并发编程。4.C 手动内存管理提供更高性能,但增加开发复杂度。

Golang在Web服务和系统编程中的应用主要体现在其简洁、高效和并发性上。1)在Web服务中,Golang通过强大的HTTP库和并发处理能力,支持创建高性能的Web应用和API。2)在系统编程中,Golang利用接近硬件的特性和对C语言的兼容性,适用于操作系统开发和嵌入式系统。

Golang和C 在性能对比中各有优劣:1.Golang适合高并发和快速开发,但垃圾回收可能影响性能;2.C 提供更高性能和硬件控制,但开发复杂度高。选择时需综合考虑项目需求和团队技能。

Golang适合高性能和并发编程场景,Python适合快速开发和数据处理。 1.Golang强调简洁和高效,适用于后端服务和微服务。 2.Python以简洁语法和丰富库着称,适用于数据科学和机器学习。


热AI工具

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

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

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

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

热门文章

热工具

SublimeText3汉化版
中文版,非常好用

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

记事本++7.3.1
好用且免费的代码编辑器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器
将Eclipse与SAP NetWeaver应用服务器集成。

SublimeText3 Linux新版
SublimeText3 Linux最新版