首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在c++中推迟函数调用

如何在c++中推迟函数调用
EN

Stack Overflow用户
提问于 2013-08-06 22:00:01
回答 6查看 684关注 0票数 18

我正在尝试延迟函数调用(使用函数包装器),方法是将其参数保存在一个空指针列表中:

代码语言:javascript
复制
void *args[]
int argt[]

使用argt是为了记住存储在void * location中的数据类型。

稍后,我需要调用被推迟的函数:

代码语言:javascript
复制
function(args[0], args[1])

但问题是我必须正确地指定它们的类型。

我使用宏,如下所示:

代码语言:javascript
复制
#define ARGTYPE(arg, type) type == CHARP ? (char *) arg : (type == LONGLONG ? *((long long *) arg) : NULL)

函数调用变成:

代码语言:javascript
复制
function(ARGTYPE(args[0], argt[0]), ARGTYPE(args[1], argt[1]))

我有两个问题:

1)警告:条件表达式中指针/整数类型不匹配,由宏定义生成(请注意,我可以接受,见2)

2)真正的问题: long long参数没有正确传递(我每次都得到0)

我显然遗漏了一些东西,所以有人能(详细地)解释一下为什么宏不能正常工作,或者建议另一种方法吗?

EDIT:我在这里添加了存储参数部分(相关细节,我解析了一个va_list),它根据格式说明符获取它们的类型:

代码语言:javascript
复制
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++;
}
EN

回答 6

Stack Overflow用户

发布于 2013-08-06 22:30:00

您的警告是由三元运算符在其子表达式中具有多种类型引起的,即:-

代码语言:javascript
复制
cond ? expression of type 1 : expression of type 2

这两个表达式需要计算为相同的类型,这对您没有多大帮助。

为了解决你的问题,我可以想到两个解决方案,这两个方案都有点糟糕。

  1. 使用VARARGS / variadic函数

使用'...‘定义您的函数参数并使用给定的宏将参数存储在某个位置,并将目标函数定义为接受va_list。您确实失去了类型安全、编译器检查、需要为函数提供额外的元数据以及重写目标函数以使用堆栈的每一项工作。

  • Drop to va_list

我告诉过你这很下流。给定一个要调用的函数:

代码语言:javascript
复制
void FuncToCall (type1 arg1, type2 arg2);

创建一个函数:

代码语言:javascript
复制
void *FuncToCallDelayed (void (*fn) (type1 arg1, type2 arg2), type1 arg1, type2 arg2);

其将堆栈上的参数复制到被返回的动态分配的存储器块。然后,当你想调用这个函数时:

代码语言:javascript
复制
void CallDelayedFunction (void *params); 

使用该指针,对FuncToCallDelayed的调用返回。然后,这会将参数推送到堆栈上,并调用函数。参数和函数指针在params参数中。

此方法确实将您绑定到特定的处理器类型,但至少在参数列表中保留了某种形式的类型检查。

更新

这是方法2的一个版本,为Visual Studio2012构建,IA32,在Win7上运行:

代码语言:javascript
复制
#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;
}

**另一个更新**

正如我在评论中提到的,还有第三种选择,那就是使用消息传递系统。不调用函数,而是创建以下形式的消息对象:-

代码语言:javascript
复制
struct MessageObject
{
   int message_id;
   int message_size;
};

struct Function1Message
{
   MessageObject base;
   // additional data
};

然后在message_id和实际函数之间进行查找,函数和查找定义如下:

代码语言:javascript
复制
void Function1 (Function1Object *message)
{
}

struct Lookup
{
  int message_id;
  void (*fn) (void *data);
};

Lookup lookups [] = { {Message1ID, (void (*) (void *data)) Function1}, etc };
票数 9
EN

Stack Overflow用户

发布于 2013-08-06 22:40:54

您的尝试失败,因为?:运算符的true和false结果操作数需要是兼容的类型。

我最初的建议是创建一个函数调用包装宏,用每种可能的组合来扩展参数,但对于您来说,这并不是一个可行的解决方案,因为您实际上希望支持的不仅仅是两种类型和两个参数。

我突然想到,你可以使用swapcontext()setcontext()来推迟通话。基本上,不是将参数隐藏到数据结构中,然后从打印函数返回以供将来调用解包隐藏的参数,而是使用swapcontext()跳转到要接管的函数,直到打印可以恢复。如果您只需要来回翻转,那么您只需要两个上下文。

代码语言:javascript
复制
struct execution_state {
    /*...*/
    ucontext_t main_ctx_;
    ucontext_t alt_ctx_;
    char alt_stack_[32*1024];
} es;

您的打印函数可能如下所示:

代码语言:javascript
复制
void deferred_print (const char *fmt, ...) {
    va_list ap;
    while (need_to_defer()) {
        /*...*/
        swapcontext(&es.main_ctx_, &es.alt_ctx_);
    }
    va_start(ap, fmt);
    vprintf(fmt, ap);
    va_end(ap);
}

其中alt_ctx_被初始化为集合函数,该集合函数接管执行直到打印可以恢复。当打印可以恢复时,将使用以下命令恢复打印上下文:

代码语言:javascript
复制
    setcontext(&es.main_ctx_);

我编写了一个玩具示例,您可以在动作here中看到它。

票数 3
EN

Stack Overflow用户

发布于 2013-08-20 03:52:14

使用foreign function call library,它会为您处理所有杂乱无章的平台特定细节。例如,下面介绍了如何延迟对带有intvoid*long long参数并返回int的函数的函数调用

代码语言:javascript
复制
#include <avcall.h>

int my_function(int a, void *b, long long c)
{
    // Do stuff
}

...

av_list alist;    // Stores the argument list
int return_value; // Receives the return value

// Initialize the argument list
av_start_int(alist, &my_function, &return_value);

// Push the arguments onto the list
av_int(alist, 42);                 // First arg 'a'
av_ptr(alist, &something);         // Second arg 'b'
av_longlong(alist, 5000000000LL);  // Third arg 'c'

// We're done -- stash away alist and return_value until we want to call the
// function later.  If the calling function needs to return, then you'll need
// to allocate those variables on the heap instead of on the stack

...

// Now we're ready to call the stashed function:
av_call(alist);
// Return value from the function is now stored in our return_value variable
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18082335

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档