所以我一直在为脚本语言制作一个自定义解析器,我希望能够只传递省略号参数。我不需要或不需要初始变量,但Microsoft和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中的匹配函数,并使用params调用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时我会发布源代码。
我并不担心便携性,所以必须要工作。此外,为了计算我做的args:
#define im_va_count(ap, num, t) {\
for(num = 0; *(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) > 0; ++num){ }\
--num;\
im_va_start(argptr);\
}
对我有用。如果有人有兴趣......
答案 0 :(得分:2)
不幸的是,这是不可能的,C标准说:
可以使用可变数量的不同类型的参数调用函数。如 在6.9.1中描述,其参数列表包含一个或多个参数。
并且...
不算作“一个或多个参数”。此外,
在访问未命名的参数之前,应调用
va_start
宏。
它应该被称为
va_start(va_list, parmN)
那个
参数
parmN
是变量中最右边参数的标识符 函数定义中的参数列表(, ...
之前的那个)。
正如您所看到的,在标准C ++中的省略号之前,如果没有至少一个参数,则不能使用可变参数函数。非便携式装配技巧是你最接近的。