我试图通过将其参数保存在void指针列表中来推迟函数调用(使用函数包装器):
void *args[]
int argt[]
Run Code Online (Sandbox Code Playgroud)
argt用于记住存储在void*位置的数据类型.
后来,我需要调用推迟的函数:
function(args[0], args[1])
Run Code Online (Sandbox Code Playgroud)
但问题是我必须正确指定他们的类型.
我使用宏,像这样:
#define ARGTYPE(arg, type) type == CHARP ? (char *) arg : (type == LONGLONG ? *((long long *) arg) : NULL)
Run Code Online (Sandbox Code Playgroud)
并且函数调用变为:
function(ARGTYPE(args[0], argt[0]), ARGTYPE(args[1], argt[1]))
Run Code Online (Sandbox Code Playgroud)
我有两个问题:
1)警告:条件表达式中的指针/整数类型不匹配,由宏定义生成(请注意我可以忍受它,见2))
2)真正的问题:long long参数没有正确传递(我每次都得0)
我显然遗漏了一些东西,所以有人可以解释(详细)为什么宏不能正常工作,或者提出另一种方法吗?
EDIT
:我在这里添加存储参数部分(相关细节,我解析一个va_list),它根据格式说明符得到它们的类型:
while (*format)
{
switch(*format)
{
case 's':
saved_arguments[i] = strdup(arg);
break;
case 'l':
saved_arguments[i] = malloc(sizeof(long long));
*((long long *) saved_arguments[i]) = arg;
break;
}
i++;
format++;
}
Run Code Online (Sandbox Code Playgroud)
您的警告是由三元运算符在其子表达式中具有多种类型引起的,即: -
cond ? expression of type 1 : expression of type 2
Run Code Online (Sandbox Code Playgroud)
这两个表达式需要评估为相同的类型,这对您没有多大帮助.
为了解决你的问题,我可以想到两个解决方案,这两个解决方案都有点讨厌.
使用VARARGS/variadic函数
使用'...'参数定义函数,并使用给定的宏将参数存储在某处,并将目标函数定义为接受va_list.您确实失去了类型安全性,编译器检查的所有内容,并且需要函数的额外元数据以及重写目标函数以使用va_list.
删除汇编程序并破解堆栈
告诉你它很讨厌.给定一个调用函数: -
void FuncToCall (type1 arg1, type2 arg2);
Run Code Online (Sandbox Code Playgroud)
创建一个功能: -
void *FuncToCallDelayed (void (*fn) (type1 arg1, type2 arg2), type1 arg1, type2 arg2);
Run Code Online (Sandbox Code Playgroud)
它将堆栈上的参数复制到动态分配的内存块中,并返回该内存块.然后,当你想要调用该函数时: -
void CallDelayedFunction (void *params);
Run Code Online (Sandbox Code Playgroud)
使用指针返回对FuncToCallDelayed的调用.然后将参数压入堆栈,并调用该函数.参数和函数指针位于params参数中.
此方法确实将您绑定到特定的处理器类型,但至少在参数列表上保留某种形式的类型检查.
更新
这是一个版本的方法2,为Visual Studio 2012,IA32构建,在Win7上运行: -
#include <iostream>
using namespace std;
__declspec (naked) void *CreateDelayedFunction ()
{
__asm
{
mov esi,ebp
mov eax,[esi]
sub eax,esi
add eax,4
push eax
call malloc
pop ecx
or eax,eax
jz error
mov edi,eax
sub ecx,4
mov [edi],ecx
add edi,4
add esi,8
rep movsb
error:
ret
}
}
void CallDelayedFunction (void *params)
{
__asm
{
mov esi,params
lodsd
sub esp,eax
mov edi,esp
shr eax,2
mov ecx,eax
lodsd
rep movsd
call eax
mov esi,params
lodsd
add esp,eax
}
}
void __cdecl TestFunction1 (int a, long long b, char *c)
{
cout << "Test Function1: a = " << a << ", b = " << b << ", c = '" << c << "'" << endl;
}
void __cdecl TestFunction2 (char *a, float b)
{
cout << "Test Function2: a = '" << a << "', b = " << b << endl;
}
#pragma optimize ("", off)
void *__cdecl TestFunction1Delayed (void (*fn) (int, long long, char *), int a, long long b, char *c)
{
return CreateDelayedFunction ();
}
void *__cdecl TestFunction2Delayed (void (*fn) (char *, float), char *a, float b)
{
return CreateDelayedFunction ();
}
#pragma optimize ("", on)
int main ()
{
cout << "Calling delayed function1" << endl;
void *params1 = TestFunction1Delayed (TestFunction1, 1, 2, "Hello");
cout << "Calling delayed function2" << endl;
void *params2 = TestFunction2Delayed (TestFunction2, "World", 3.14192654f);
cout << "Delaying a bit..." << endl;
cout << "Doing Function2..." << endl;
CallDelayedFunction (params2);
cout << "Doing Function1..." << endl;
CallDelayedFunction (params1);
cout << "Done" << endl;
}
Run Code Online (Sandbox Code Playgroud)
**另一个更新**
正如我在评论中提到的,还有第三种选择,即使用消息传递系统.而不是调用函数,创建一个形式的消息对象: -
struct MessageObject
{
int message_id;
int message_size;
};
struct Function1Message
{
MessageObject base;
// additional data
};
Run Code Online (Sandbox Code Playgroud)
然后在message_id和实际函数之间进行查找,函数和查找定义如下: -
void Function1 (Function1Object *message)
{
}
struct Lookup
{
int message_id;
void (*fn) (void *data);
};
Lookup lookups [] = { {Message1ID, (void (*) (void *data)) Function1}, etc };
Run Code Online (Sandbox Code Playgroud)
wra*_*erm -1
你为什么不使用g_timeout_add_seconds()
设置一个以默认优先级 G_PRIORITY_DEFAULT 定期调用的函数。该函数会被重复调用,直到返回FALSE,此时超时自动销毁,该函数不会再次被调用。