java和c语言变长参数的底层实现区别

java和c语言变长参数的底层实现存在着区别

java其实是一个语法糖
类似

private static int sumUp(int... values) {
}

其实最后编译时会转化为
实际上是传递了一个数组引用

private static int sumUp(int[] values) {
}

所以如果同时写这两个函数,就会编译不通过,他们本质上是一样的



而c语言的变长参数就要说到函数调用约定了
我们都知道 c语言编译之后调用函数的汇编形式如下

push eax
push ebx
....
call xxx

即将数据压栈之后,调用方法
因为将数据压栈之后栈指针会变化,所以需要有一个清栈操作



清栈方式主要分为3种

cdecl 由调用者处理栈 常用于c/c++语言
即实际上函数内不包括清栈的代码,而是由调用者在函数返回之后进行清栈
类似这样的形式

push eax
push ebx
call xxx
add esp,8


stdcall 由被调用者清理栈 常用于win32api
即在函数结束但还没有返回之前清栈

(某个函数内部)
add esp,8
ret


fastcall与stdcall基本类似,但是会优先使用寄存器传递部分参数



前面也提到了c语言使用的是cdecl的方式,由调用者本身清理栈,那么他有什么好处呢?

先考虑如果被调用者清理栈会是什么后果,即stdcall,在此模式下,函数内部的清栈语句是写死的,所以能够接受的参数在一开始就确定了,比如这个函数能够接受两个参数
最后在函数返回之前就会把esp指针加上8

而cdecl由于是调用者清栈,清栈语句是写在函数外面的,所以完全可以达到传几个参数,就清多少栈,比如ab两个地方调用一个函数,a传了两个int,b传了3个int
则a返回时 esp+8,b返回时esp+12

正是由于c语言的使用cdecl调用约定,才可以实现真正意义上的变长参数,和java的变长参数底层实现是完全不一样的


欢迎关注我的github https://github.com/luckyCatMiao

你可能感兴趣的:(汇编,java,c语言,汇编语言,汇编)