通过指针调用具有未知参数计数的函数的简单方法
我有以下代码:
typedef void * (__stdcall * call_generic)(...);
typedef void * (__stdcall * call_push2)(unsigned long,unsigned long);
void * pfunc;
// assume pfunc is a valid pointer to external function
// this is a logically correct way of calling, however this includes:
// add esp, 8
// after the call, and that breaks my stack.
((call_generic)pfunc)(1,1);
// however, if i use this call:
((call_push2)pfunc)(1,1);
// this does not happen and code works properly.
手动跟踪所有调用并计算参数是很痛苦的(前面有很多这样的调用),我更喜欢宏或其他东西,但由于该错误,这是不可能的。
有解决办法吗?是否有另一种创建 call_generic 类型来执行此类操作的方法?
我真的不明白为什么它会进行“清理”,但这会严重破坏我的堆栈,导致以前定义的变量丢失。
I have the following code:
typedef void * (__stdcall * call_generic)(...);
typedef void * (__stdcall * call_push2)(unsigned long,unsigned long);
void * pfunc;
// assume pfunc is a valid pointer to external function
// this is a logically correct way of calling, however this includes:
// add esp, 8
// after the call, and that breaks my stack.
((call_generic)pfunc)(1,1);
// however, if i use this call:
((call_push2)pfunc)(1,1);
// this does not happen and code works properly.
It's a pain to track all the calls and count args manually (there are lots of such calls ahead), I'd prefer a macro or something for this, but with that bug it's not possible.
Is there a solution? Is there another way of creating call_generic
type to do such things?
I do not really understand why exactly it does that "cleanup" but that breaks my stack badly, causing previously defined variables to be lost.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
((call_generic)pfunc)(1,1);
仅当pfunc
指向的函数实际上具有您转换为的签名时,才是逻辑上正确的调用方式,<代码>void *(...)。您的代码告诉编译器进行可变参数调用,因此它会进行可变参数调用。对不是 varargs 函数的函数进行 varargs 调用不起作用(在这种情况下,对于谁必须清理堆栈存在分歧,并且完成了两次)。没有办法免费做到这一点。在调用之前,您必须以某种方式将函数指针转换为正确的签名,否则调用代码不知道如何以被调用者代码可以使用的方式传递参数。
一种选择是确保 pfunc 可能指向的所有被调用函数具有相同的签名,然后转换为该类型。例如,您可以将它们设为所有可变参数函数,尽管我并不特别推荐它。做您不想做的事情会更安全 - 确保此处可能出现的所有函数都采用两个
unsigned long
,并强制转换为call_push2
。((call_generic)pfunc)(1,1);
is only a logically correct way of calling if the function pointed to bypfunc
actually has the signature you cast to,void *(...)
. Your code tells the compiler to make a varargs call, so it makes a varargs call. A varargs call to a function that isn't a varargs function doesn't work (in this case, there's disagreement who has to clean up the stack, and it gets done twice).There's no way to do this for free. You must somehow cast the function pointer to the correct signature before calling it, otherwise the calling code doesn't know how to pass the parameters in a way that the callee code can use.
One option is to ensure that all the called functions that
pfunc
might point to have the same signature, then cast to that type. For example, you could make them all varargs functions, although I don't particularly recommend it. It would be more type safe to do what you don't want to - make sure that all the functions that might appear here take twounsigned long
, and cast tocall_push2
.call_generic
的技巧不适用于应使用__stdcall
调用约定调用的函数。这是因为__stdcall
暗示函数应该清理堆栈,OTOH 可变参数函数(带有...
参数的函数)可能不会这样做,因为它们不知道论据。因此,使用 __stdcall 调用约定来标记可变参数函数就像搬起石头砸自己的脚。
在你的具体情况下,我会进入宏写作方向。我看不出有什么小技巧可以满足您的需求。
编辑
其中一种技术可能是使用模板类。例如:
您需要为每个参数数量(0、1、2、3、...)创建这样一个类。
不用说这个方法是“不安全的”——即没有对函数调用的正确性进行编译时验证。
The trick with
call_generic
won't work with functions that should be called with__stdcall
calling convention. This is because__stdcall
implies that the function should clean the stack, OTOH variadic functions (those with...
arguments) may not do this, since they are not aware of the arguments.So that marking a variadic function with
__stdcall
calling convention is like shooting yourself in the foot.In your specific case I'd go in the macro writing direction. I don't see a trivial trick that'd acomplish what you need.
EDIT
One of the techniques may be using template classes. For instance:
You'll need to create such a class for every number of arguments (0, 1, 2, 3, ...).
Needless to say this method is "unsafe" - i.e. there is no compile-time validation of the correctness of the function call.
在我看来,您想要一种动态函数绑定机制,它将指针绑定到从调用中推导的原型。这通常需要元编程,为此 boost::bind或者来自 boost 函数库的其他东西是你最好的选择(如果他们没有它,我怀疑我能否做到)。
seems to me you want a form of dynamic function binding mechanism that will bind a pointer to a protoype deducted from an invocation. This generally requires metaprogramming, for this boost::bind or something else from the boost functions library is your best bet (and if they don't have it, its doubtful that i can be done).