如何将 list 转换成可变长参数?

2019-01-29 14:05:53 +08:00
 icemanpro
现有一函数 void foo(int count,...) ,因参数长度是在运行时才确定的,现将参数放入到一 list 中,如何调用 foo ,并将 list 做为参数传给 foo?
3464 次点击
所在节点    C
11 条回复
eritpchy
2019-01-29 14:12:57 +08:00
直接传递 va_list 会好点
GeruzoniAnsasu
2019-01-29 14:16:44 +08:00
本来想说不能这么传

然后再看了几遍。。。。foo 是已存在已定义不可改的接口吗。。那我觉得没有写法能帮你

va_list 在 x64 上没法用
icyalala
2019-01-29 14:22:39 +08:00
试试 libffi
@GeruzoniAnsasu va_list 在 x64 上为什么没法用?
GeruzoniAnsasu
2019-01-29 14:48:35 +08:00
@icyalala 其实是不太想解释

首先如果是传参数进来,在函数里用 va_系列宏去解开传进来的变长参数,是可以用的,因为 x64 默认的 fastcall 约定虽然用寄存器传参,但会在栈上放一个副本,还是有地址可引用。不过放副本这个操作是被调函数的 prologue 做的,从外面打包参数进来的时候前 4 个参数还是只会通过寄存器传递。

如果非要 hack 的话确实可以内嵌一下汇编先把前 4 个参数放进寄存器其余的压栈,但这样 hack 的话连 call 也必须要用汇编嵌进去并且返回后手动 add rsp 恢复栈平衡,更要命的是在 win 和 linux 上同样是 fastcall 约定用到的寄存器还不一样,还得针对平台写两套汇编

虽然总共代码也不多,但总觉得崩的可能性太大了,想强迫 lz 先想其它的方法解决
GeruzoniAnsasu
2019-01-29 14:55:07 +08:00
啊。。。原来 fastcall 是用 6 个寄存器
icyalala
2019-01-29 15:33:03 +08:00
@GeruzoniAnsasu calling convention 不单只有 fastcall,参数也不单是 integer 类型,没必要重新实现一遍 libffi 嘛。。
catror
2019-01-29 15:37:53 +08:00
enenaaa
2019-01-29 15:38:47 +08:00
@GeruzoniAnsasu 不定参数调用使用__cdecl 方式吧。 跟 fastcall 有啥关系。
pursuer
2019-01-29 15:48:40 +08:00
@enenaaa
x86_64 操作系统规定的 abi 好像已经统一成类似 fastcall 的寄存器传参了,而且不同操作系统的 abi 还不一样
GeruzoniAnsasu
2019-01-29 16:45:38 +08:00
@icyalala
@catror
@enenaaa
可以理解为,x64 只有一种调用约定,但有两个不同平台版本的实现
尝试在编译到 x64 的源码函数上声明 stdcall 或 cdecl 都会被编译器忽略

另外不定参函数这种东西,在 C++中必定是与变参模板同时存在的,在 C 中,变参函数实际上就是变参泛型的 approach, “运行时不定个数”类的东西不会用变参函数来写,一定会封装成某种数据结构并把指针传进去。无论 C 还是 C++,变参函数都是用来方便“静态不定个数参数的调用”的,C++通过变参模板给它加了更强的约束而已。

所以最开始就想说,参数不能像 lz 设想的那样传,传一个“运行时不定长”的东西给变参函数本来就是错误的做法
eritpchy
2019-01-29 16:54:06 +08:00
https://stackoverflow.com/a/3968787
代码虽丑但可以解决问题

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/531565

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX