golang-函数

摘要:
C语言使用寄存器和堆栈传递参数,eax寄存器传递返回值;Go语言使用堆栈传递参数和返回值。

查看生成的汇编代码
go tool compile -S xx.go //编译器对汇编代码进行优化

go tool compile -S -N -l xx.go      //不优化

注:如果编译时不使用 -N -l 参数,编译器会对汇编代码进行优化,编译结果会有较大差别

c语言汇编分析

// ch04/my_function.c
int my_function(int arg1, int arg2) {
return arg1 + arg2;
}

int main() {
int i = my_function(1, 2);
}

cc -S my_function.c

当我们在 x86_64 的机器上使用 C 语言中调用函数时,参数都是通过寄存器和栈传递的,其中:

六个以及六个以下的参数会按照顺序分别使用 edi、esi、edx、ecx、r8d 和 r9d 六个寄存器传递;
六个以上的参数会使用栈传递,函数的参数会以从右到左的顺序依次存入栈中;
而函数的返回值是通过 eax 寄存器进行传递的,由于只使用一个寄存器存储返回值,所以 C 语言的函数不能同时返回多个值。

go语言汇编分析

//main.go
package main

func myFunction(a, b int) (int, int) {
return a + b, a - b
}

func main() {
myFunction(66, 77)
}

go tool compile -S -N -l main.go

Go 语言使用栈传递参数和接收返回值,所以它只需要在栈上多分配一些内存就可以返回多个值。

总结:
C 语言和 Go 语言在设计函数的调用惯例时选择了不同的实现。C 语言同时使用寄存器和栈传递参数,使用 eax 寄存器传递返回值;而 Go 语言使用栈传递参数和返回值。我们可以对比一下这两种设计的优点和缺点:

C 语言的方式能够极大地减少函数调用的额外开销,但是也增加了实现的复杂度;
CPU 访问栈的开销比访问寄存器高几十倍3;
需要单独处理函数参数过多的情况;
Go 语言的方式能够降低实现的复杂度并支持多返回值,但是牺牲了函数调用的性能;
不需要考虑超过寄存器数量的参数应该如何传递;
不需要考虑不同架构上的寄存器差异;
函数入参和出参的内存空间需要在栈上进行分配;
Go 语言使用栈作为参数和返回值传递的方法是综合考虑后的设计,选择这种设计意味着编译器会更加简单、更容易维护。

Go 语言函数调用惯例:
Go 通过栈传递函数的参数和返回值,在调用函数之前会在栈上为返回值分配合适的内存空间,随后将入参从右到左按顺序压栈并拷贝参数,返回值会被存储到调用方预留好的栈空间上,我们可以简单总结出以下几条规则:

通过堆栈传递参数,入栈的顺序是从右到左;
函数返回值通过堆栈传递并由调用者预先分配内存空间;
调用函数时都是传值,接收方会对入参进行复制再计算;

附图:go汇编的分析过程

golang-函数第1张

引用:

https://draveness.me/golang/docs/part2-foundation/ch04-basic/golang-function-call/

https://chai2010.cn/advanced-go-programming-book/ch3-asm/ch3-04-func.html

免责声明:文章转载自《golang-函数》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇php checkbox 复选框C#-Xamarin的Android项目开发(二)——控件应用下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Golang邮件发送

简介: 电子邮件的应用非常广泛,常见在某网站注册一个账号,自动发送一封激活邮件,通过邮件找回密码,自动批量发送活动信息等等。这些应用不可能与平时发邮件一样,先打开浏览器,登录邮箱在发送。 如何通过Go语言代码来创建电子邮件,并连接邮件服务器发送邮件? 电子邮件在网络中传输和网页一样需要遵守特定的协议。常见的电子邮件协议包括:SMTP,POP3,LMAP。其...

golang 并发程序写入map两种实现方式sync.Mutex和chan的效率对比

golang原生的数据结构map,由于是通过hash方式实现的,不支持并发写入,但是在golang很多并发场景中,不可避免的需要写入map,下面介绍两种解决map并发写入的实现方式: sync.Mutex互斥锁(通过加锁解锁解决map不能并发写入的问题) chan (通过管道来解决map并发的问题),chan的存在完美解决goroutine之间的通信以及...

golang实现命令行程序的使用帮助

通过flag包我们可以很方便的实现命令行程序的参数标志,接下来我们来看看如何实现命令行程序的使用帮助,通常以参数标志-h或--help的形式来使用. 自动生成使用帮助 我们只需要声明其他参数标志,并执行解析,flag包会帮我们自动生成使用帮助. //main.go //输出2个数,输出较大的数 package main import (...

Golang基础编程(四)-Map(集合)、Slice(切片)、Range

一、Map ·Map 是一种无序的键值对的集合。Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。 ·Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map 是无序的,我们无法决定它的返回顺序,这是因为 Map 是使用 hash 表来实现的。 Map-声明&初始化 Map使用前必须初始化 Ma...

golang学习笔记---reflect包

go语言提供了一种机制,在编译时不知道类型的情况下,可更新变量,在运行时查看值,调用方法以及直接对他们的布局进行操作。这种机制称为反射(reflection)。 为什么使用反射 有时候我们需要写一个函数有能力统一处理各种值类型的函数,而这些类型可能无法共享同一个接口,也可能布局未知,也有可能这个类型在我们设计函数时还不存在。甚至这个类会同时存在上面三个问...

golang之vscode环境配置

go语言开发,选择vscode作为IDE工具也是一个不错的选择,毕竟goland收费,老是破解也挺麻烦,除了这点,不过说实话挺好用的。vscode的话相对来说就毕竟原始,适合初学者。 1、vscode首先需要安装go语言插件,在vscode扩展中搜索“go”,如下图,下载安装go插件 2、vscode环境配置  打开vscode设置,菜单File -&g...