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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

GO의 핵심 기능에는 쓰레기 수집, 정적 연결 및 동시성 지원이 포함됩니다. 1. Go Language의 동시성 모델은 고루틴 및 채널을 통한 효율적인 동시 프로그래밍을 실현합니다. 2. 인터페이스 및 다형성은 인터페이스 방법을 통해 구현되므로 서로 다른 유형을 통일 된 방식으로 처리 할 수 있습니다. 3. 기본 사용법은 기능 정의 및 호출의 효율성을 보여줍니다. 4. 고급 사용에서 슬라이스는 동적 크기 조정의 강력한 기능을 제공합니다. 5. 레이스 조건과 같은 일반적인 오류는 Getest-race를 통해 감지 및 해결할 수 있습니다. 6. 성능 최적화는 sync.pool을 통해 개체를 재사용하여 쓰레기 수집 압력을 줄입니다.

Go Language는 효율적이고 확장 가능한 시스템을 구축하는 데 잘 작동합니다. 장점은 다음과 같습니다. 1. 고성능 : 기계 코드로 컴파일, 빠른 달리기 속도; 2. 동시 프로그래밍 : 고어 라틴 및 채널을 통한 멀티 태스킹 단순화; 3. 단순성 : 간결한 구문, 학습 및 유지 보수 비용 절감; 4. 크로스 플랫폼 : 크로스 플랫폼 컴파일, 쉬운 배포를 지원합니다.

SQL 쿼리 결과의 정렬에 대해 혼란스러워합니다. SQL을 학습하는 과정에서 종종 혼란스러운 문제가 발생합니다. 최근 저자는 "Mick-SQL 기본 사항"을 읽고 있습니다.

기술 스택 컨버전스와 기술 선택의 관계, 소프트웨어 개발에서 기술 스택의 선택 및 관리는 매우 중요한 문제입니다. 최근에 일부 독자들은 ...

골란 ...

GO 언어로 세 가지 구조를 비교하고 처리하는 방법. GO 프로그래밍에서는 때때로 두 구조의 차이점을 비교하고 이러한 차이점을 ...에 적용해야합니다.

GO에서 전 세계적으로 설치된 패키지를 보는 방법? Go Language로 발전하는 과정에서 Go는 종종 사용합니다 ...

골란드의 사용자 정의 구조 레이블이 표시되지 않으면 어떻게해야합니까? Go Language 개발을 위해 Goland를 사용할 때 많은 개발자가 사용자 정의 구조 태그를 만날 것입니다 ...


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

에디트플러스 중국어 크랙 버전
작은 크기, 구문 강조, 코드 프롬프트 기능을 지원하지 않음

SublimeText3 Linux 새 버전
SublimeText3 Linux 최신 버전

WebStorm Mac 버전
유용한 JavaScript 개발 도구

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

Atom Editor Mac 버전 다운로드
가장 인기 있는 오픈 소스 편집기
