【问题标题】:Getting ellipses function parameters without an initial argument获取没有初始参数的省略号函数参数
【发布时间】:2012-10-27 04:10:51
【问题描述】:

所以我一直在为脚本语言制作一个自定义解析器,并且我希望能够只传递省略号参数。我不需要也不想要一个初始变量,但是微软和 C 似乎想要别的东西。仅供参考,请参阅底部的信息。

我查看了 va_* 定义

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

而我不想要的部分是 va_start 中的 v。作为一个小背景,我在 goasm 方面很有能力,而且我知道堆栈是如何工作的,所以我知道这里发生了什么。我想知道是否有一种方法可以在不使用内联汇编的情况下获取函数堆栈库。

我的想法:

#define im_va_start(ap) (__asm { mov [ap], ebp })

等等……但我真的觉得那很乱,我做错了。

struct function_table {
    const char* fname;
    (void)(*fptr)(...);
    unsigned char maxArgs;
};
function_table mytable[] = {
{ "MessageBox", &tMessageBoxA, 4 } };

... 某个函数通过传递给它的 const char* 进行排序,以在 mytable 中找到匹配的函数并使用参数调用 tMessageBoxA。此外, maxArgs 参数只是为了检查是否正在发送有效数量的参数。我不想在函数中发送它有个人原因,但同时我们可以说这是因为我很好奇。

这只是一个例子;自定义库是我将要实现的,因此它不仅仅是调用 WinAPI 的东西。

void tMessageBoxA(...) {
// stuff to load args passed
MessageBoxA(arg1, arg2, arg3, arg4);
}

我正在使用 __cdecl 调用约定,并且我已经查找了可靠地获取指向堆栈底部(而不是顶部)的指针的方法,但我似乎找不到任何方法。另外,我不担心函数安全或类型检查。


编辑:感谢您的意见,看来这是不可能的。

我的修复最终是

    #define im_va_start(ap) {\
        __asm push eax\
        __asm mov eax, ebp\
        __asm add eax, 8h\
        __asm mov ap, eax\
        __asm pop eax\
    }

然后我可以正常继续。

至于我为什么需要它,我正在做一些(独特的)阅读:不安全的技巧,并使用带有指向上述函数的指针的结构数组。由于每个功能都是独一无二的,而且大多数都来自我的自定义库,因此它们具有......不同的行为。我真的不知道如何解释,但我会在完成 POC 后发布源代码。

我并不真正担心便携性,所以它必须起作用。另外,为了计算我所做的参数:

#define im_va_count(ap, num, t) {\
for(num = 0; *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) > 0; ++num){ }\
--num;\
im_va_start(argptr);\
}

这对我有用。如果有人有兴趣...

【问题讨论】:

  • 我想问一下,你看过可变参数模板吗?顺便说一句,这是一个很好的问题。
  • 如果你的函数对传递给它的参数一无所知,它将如何做任何事情?
  • 他显然有一些逻辑在他的程序中这样做,这个提问者似乎没有足够的无知,不会想到这样简单的事情。
  • 如何知道传递了多少个参数?关于其余参数的信息必须在所需参数之一中(如在 printf 的格式字符串中),或者您扫描参数直到到达结束标记。无论哪种方式,都必须至少有一个论据。
  • @SethCarnegie:我只是好奇。我不知道它会怎么做。有一个全局变量来指示可能传递了多少个参数?

标签: c++ parsing variadic-functions


【解决方案1】:

不幸的是,这是不可能的,C 标准说:

可以使用可变数量的不同类型的参数调用函数。作为 6.9.1中描述的,其参数列表包含一个或多个参数。

并且... 不算作“一个或多个参数”。此外,

va_start 宏应在访问未命名参数之前调用。

应该这样称呼它

va_start(va_list, parmN)

还有那个

参数parmN是变量中最右边参数的标识符 函数定义中的参数列表(, ... 之前的那个)。

如您所见,在标准 C++ 中的省略号之前,您不能拥有一个没有至少一个参数的可变参数函数。非便携式组装技巧是您能找到的最接近的技巧。

【讨论】:

    猜你喜欢
    • 2022-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2013-06-27
    • 2022-01-24
    • 2015-01-26
    • 1970-01-01
    相关资源
    最近更新 更多