V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
icemanpro
V2EX  ›  C

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

  •  
  •   icemanpro · 2019-01-29 14:05:53 +08:00 · 3319 次点击
    这是一个创建于 1886 天前的主题,其中的信息可能已经有所发展或是发生改变。
    现有一函数 void foo(int count,...) ,因参数长度是在运行时才确定的,现将参数放入到一 list 中,如何调用 foo ,并将 list 做为参数传给 foo?
    11 条回复    2019-01-29 16:54:06 +08:00
    eritpchy
        1
    eritpchy  
       2019-01-29 14:12:57 +08:00
    直接传递 va_list 会好点
    GeruzoniAnsasu
        2
    GeruzoniAnsasu  
       2019-01-29 14:16:44 +08:00
    本来想说不能这么传

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

    va_list 在 x64 上没法用
    icyalala
        3
    icyalala  
       2019-01-29 14:22:39 +08:00
    试试 libffi
    @GeruzoniAnsasu va_list 在 x64 上为什么没法用?
    GeruzoniAnsasu
        4
    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
        5
    GeruzoniAnsasu  
       2019-01-29 14:55:07 +08:00
    啊。。。原来 fastcall 是用 6 个寄存器
    icyalala
        6
    icyalala  
       2019-01-29 15:33:03 +08:00
    @GeruzoniAnsasu calling convention 不单只有 fastcall,参数也不单是 integer 类型,没必要重新实现一遍 libffi 嘛。。
    catror
        7
    catror  
       2019-01-29 15:37:53 +08:00
    enenaaa
        8
    enenaaa  
       2019-01-29 15:38:47 +08:00
    @GeruzoniAnsasu 不定参数调用使用__cdecl 方式吧。 跟 fastcall 有啥关系。
    pursuer
        9
    pursuer  
       2019-01-29 15:48:40 +08:00
    @enenaaa
    x86_64 操作系统规定的 abi 好像已经统一成类似 fastcall 的寄存器传参了,而且不同操作系统的 abi 还不一样
    GeruzoniAnsasu
        10
    GeruzoniAnsasu  
       2019-01-29 16:45:38 +08:00
    @icyalala
    @catror
    @enenaaa
    可以理解为,x64 只有一种调用约定,但有两个不同平台版本的实现
    尝试在编译到 x64 的源码函数上声明 stdcall 或 cdecl 都会被编译器忽略

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

    所以最开始就想说,参数不能像 lz 设想的那样传,传一个“运行时不定长”的东西给变参函数本来就是错误的做法
    eritpchy
        11
    eritpchy  
       2019-01-29 16:54:06 +08:00
    https://stackoverflow.com/a/3968787
    代码虽丑但可以解决问题
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5397 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 09:01 · PVG 17:01 · LAX 02:01 · JFK 05:01
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.