如何在C中用前缀和后缀包装函数

时间:2017-10-27 13:10:06

标签: c design-patterns

我想知道如何解决包装问题 Stroustrup paper但是在C.我正试图找到一种有效的方式来调用

// prefix
GenericFunctionCallThatCouldHaveAnyNumberOfArgs();
// suffix

我考虑过创建一个代理函数,它接受一个输入函数指针,但我想要包装的函数并不都具有相同的函数签名。

我目前的解决方案是创建一个宏:

#define CALL(func) prefix; func; suffix;
CALL(myfunction(a, 'b', 1))

它有效,但它使代码更难理解,特别是当前缀和后缀很复杂时。前缀和后缀也不一定是对函数的调用,它们也可以是封装。在C中是否有一种设计模式能够有效地(在代码行方面)实现这一点,同时仍然保持可读性。

2 个答案:

答案 0 :(得分:1)

对于返回类型void的函数调用,您可以使用comma operator,它有一些限制 - 允许指定一个接一个地计算的表达式,包括函数调用。

例如,你可以写

#define prefix printf("something in prefix\n")
#define suffix printf("something as suffix\n")
void someFunction(int x) {
    printf("some function, parameter value %d\n", x);
}

#define CALL(func) (prefix,func,suffix)

int main() {

    CALL(someFunction(10));
}

输出:

something in prefix
some function, parameter value 10
something as suffix

在逗号运算符中使用的表达式有几个限制。例如,您无法在此类表达式的过程中定义变量。但是,有一些策略可以克服这个问题,例如:通过引入全局变量或通过调用函数(当然可以定义局部变量)。

返回类型void的原因是你想要在中间调用你的函数,即不是逗号运算符中的最后一个表达式,但是逗号运算符per的结果总是值最后一个表达式计算的结果。请进一步注意,使用#define CALL(func) - 方法prefixsuffix中的任何更改都需要重新编译您的程序。但我认为无论如何你都知道这一点。

希望它有所帮助。

答案 1 :(得分:1)

  

我考虑过创建一个代理函数,它接受一个输入函数指针,但我想要包装的函数并不都具有相同的函数签名。

这可以通过添加另一层间接来解决。但是,它不会使代码更短。

假设我们想要使用相同的前缀/后缀代码调用两个函数foo()(不传递参数)和bar(42, "hello")(两个不同类型的参数)。

我们可以这样做:

void call_decorated(void (*f)(void *), void *p) {
    printf("prefix code\n");
    f(p);
    printf("suffix code\n");
}

这允许我们调用任何带有单个void *参数的函数。要在foobar中使用它,我们必须编写适配器函数:

void wrap_foo(void *p) {
    foo();
}

struct bar_args {
    int n;
    const char *s;
};

void wrap_bar(void *p) {
    struct bar_args *args = p;
    bar(args->n, args->s);
}

现在我们可以这样调用call_decorated

call_decorated(wrap_foo, NULL);

struct bar_args args = { 42, "hello" };
call_decorated(wrap_bar, &args);

这非常繁琐,但源中只有一个前缀/后缀代码实例。