【问题标题】:What is better for the parameters of a C callback function: va_list, or ellipsis?C 回调函数的参数哪个更好:va_list 或省略号?
【发布时间】:2011-05-01 08:08:13
【问题描述】:

我的图书馆提供了一个回调点,我的图书馆用户可以在其中注册以获取信息。回调的一般形式是int,后跟各种类型取决于 int 值的参数。因此,我定义了回调类型和设置它的函数如下。

typedef void (* callback_func_t)(int type, ...);
void set_callback_func(callback_func_t callback);

在我的库中,我一直在调用这个函数,作为用户设置的函数,或者我提供的默认函数。它有效。

现在,我想添加一个间接级别,以便能够调用多个已注册的回调。问题是我的内部回调函数仍然需要省略号参数,也必须调用带有省略号的回调函数。因此,我的内部函数必须解释 type,从 va_list 解包参数并将它们作为参数提供给 callbacj 函数。

void internal_callback(int type, ...) {
    va_list args;
    va_start(args, type);
    switch (type) {
    case 0: call_callback(type, va_arg(args, int)); break;
    // ...
    }
    va_end(args);
}

但是,在用户执行回调的时候,也会有同样的va_list用法,以及参数的解释,根据type的值。解决方法是直接将va_list作为参数传递给回调函数,使得内部回调函数的实现显而易见。

typedef void (* callback_func_t)(int type, va_list args);

我的问题是:定义一个以va_list 作为参数的回调函数类型是一种好习惯吗?我可以像上面那样定义我的回调函数类型,但是和上面的定义相比,有什么优缺点呢?

【问题讨论】:

    标签: c callback ellipsis variadic-functions


    【解决方案1】:

    我假设类型的数量是有限且已知的?如果是这样,为什么不使用枚举和联合来实现某种程度的类型安全,这也可以解决您的问题:

    enum callback_arg_type { INT_ARG, DOUBLE_ARG, VECTOR_ARG };
    
    union callback_arg
    {
        int as_int;
        double as_double;
        struct { double x, y, z; } as_vector;
    };
    
    typedef void (*callback_func_t)(
        enum callback_arg_type type, union callback_arg arg);
    

    根据参数大小的不同,传递指针可能是个好主意。您还可以提供一些宏来为回调调用提供更好的语法,但如果它们只是从您的库中调用,则可能不值得:

    union callback_arg arg = { .as_int = 42 };
    callback_fn(INT_ARG, arg);
    

    本身就很短。

    【讨论】:

      【解决方案2】:

      我会选择va_list 版本。用户已经在处理与va_lists 打交道的恐惧,因此您不会通过向他们隐藏任何东西来保存任何东西。

      另外使用列表而不是尝试重新传递参数将减少堆栈的使用。如果您必须将参数重新传递给它们的函数,它将生成所有这些参数的新副本,但传递 va_list 类型将只使用堆栈中已经存在的这些参数的实例。

      最后,您的代码将更简单(如果我正确理解了问题),并且您将让每个用户不必调用 va_startva_end(这可能不会更改他们的输出代码对于stdarg 的大多数实现来说功能很多)但否则他们都必须键入这些调用并且(取决于stdargs 在平台上的实现方式)他们需要确保他们在返回之前确实确实调用了va_end(如果在发生错误的情况下提前返回很容易错过)。

      【讨论】:

        猜你喜欢
        • 2017-05-12
        • 2017-03-27
        • 2015-02-11
        • 2012-06-14
        • 2010-10-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多