如何推迟c中的函数调用?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (27)

我试图推迟一个函数调用(使用函数包装),通过将其参数保存在void指针列表中:

void *args[]
int argt[]

argt用于记住存储在void *位置的数据类型。

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

function(args[0], args[1])

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

我使用一个宏,如下所示:

#define ARGTYPE(arg, type) type == CHARP ? (char *) arg : (type == LONGLONG ? *((long long *) arg) : NULL)

函数调用变为:

function(ARGTYPE(args[0], argt[0]), ARGTYPE(args[1], argt[1]))

我有两个问题:

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

2)真正的问题:长长的参数没有正确传递(我每次都得到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++;
}
提问于
用户回答回答于

因为运算?:符的真假结果操作数需要是兼容类型。

我想到你可以使用swapcontext()setcontext()。基本上,不是将参数隐藏到数据结构中,而是从打印函数返回,以便将来调用解开存储的参数,然后使用swapcontext()它跳转到要接管的函数,直到打印可以恢复为止。如果你只需要来回翻转,你只需要两个上下文。

struct execution_state {
    /*...*/
    ucontext_t main_ctx_;
    ucontext_t alt_ctx_;
    char alt_stack_[32*1024];
} es;

你的打印功能可能如下所示:

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_被初始化为接管执行直到打印可以恢复的集合函数。当打印可以恢复时,打印上下文恢复为:

    setcontext(&es.main_ctx_);
用户回答回答于

你的警告是由在其子表达式中具有多种类型的三元操作符引起的,即:

cond ? expression of type 1 : expression of type 2

这两个表达式需要评估到相同的类型,这对你没有多大的帮助。

为了解决你的问题,我可以考虑两种解决方案,这两种解决方案都有点令人讨厌。

  1. 使用VARARGS / variadic函数 使用'...'参数定义函数,并使用给定的宏存储参数,并将目标函数定义为接受va_list。你确实会失去每一种类型的安全性,编译器检查,并且需要为这些函数额外的元数据以及重写目标函数来使用va_list。
  2. 掉到汇编程序并破解堆栈

告诉你这是讨厌的。给定一个函数来调用:

void FuncToCall (type1 arg1, type2 arg2);

创建一个功能:

void *FuncToCallDelayed (void (*fn) (type1 arg1, type2 arg2), type1 arg1, type2 arg2);

它将堆栈中的参数复制到返回的动态分配的内存块中。然后,当你想调用这个函数时:

void CallDelayedFunction (void *params); 

指针调用FuncToCallDelayed返回。然后这将参数推入堆栈,并调用该函数。参数和函数指针位于params参数中。

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

扫码关注云+社区