C中类似Python的函数修饰符

问题描述 投票:0回答:1

我正在尝试使用函数指针在C中实现类似Python的函数装饰器,但出现奇怪的分段错误。

想法是我们有一个decorator函数,该函数具有内部函数wrapper。然后,装饰器将some_function作为参数,将其与其他代码一起放入wrapper中,并返回wrapper函数。

Python中非常简单的函数装饰器:

def decorator(f):
  def wrapper():
    #do something before
    f()
    #do something after
  return wrapper

def some_func():
  print('Hello')

some_func = decorator(some_func)

[我知道Python与C不同,它把函数当作一类对象,但是我想知道是否可以通过使用函数指针在C中模拟相同类型的功能。

我尝试过此

void* do_twice(void (*func)())
{
  auto void wrapper()
  { 
    func();
    func(); 
  }

  return &wrapper;
}

void some_func()
{ printf("Hello\n"); }

int main()
{
  void (*fun_ptr)() = &some_func;
  fun_ptr = decorator(fun_ptr);
  fun_ptr();
  return 0;
}

输出

Hello
Segmentation fault

现在是有趣的地方。如果我在wrapper中这样声明一个变量:

  auto void wrapper()
  {
    int blah=5;
    func();
    func();
  }

然后细分错误已修复。有人可以解释为什么会这样吗?显然我的指针做错了,代码也非常不稳定-似乎对main函数的不相关添加会导致分段错误再次弹出。

c
1个回答
0
投票

您允许我游览C ++吗?在这种语言中,有函子对象,它们是可以像函数一样调用的结构:

 struct Wrapper
 {
     /* this is what allows the struct to be called like a function: */
     void operator()(/* can define arbitrary parameters here */)
     { /* some implementation */ }
 };

换句话说,这将允许您编写如下代码:

 Wrapper w; // actually, C++ does more here than C, but that's out of
            // scope of this question...
 w(); // possible due to the operator() defined above

好,现在让我们扩展一下:

 struct Wrapper
 {
     void(*m_f)(void); /* !!! */

     void operator()(void) /* don't want any parameters... */
     {
         printf("before\n");
         m_f();
         printf("after\n");
     }
 };

[不想进一步深入,现在C ++开发人员将处理可访问性(这样,成员m_f仅可在类内部使用),并提供所谓的构造函数(用于初始化m_f成员适当地)。有了所有这些,使用包装器类的最终C ++代码可能看起来像:

 Wrapper decorate(void(*f)(void))
 {
     return Wrapper(f); // the fore-mentioned constructor gets called    
 }

 void test(void) { /* do something */ }

 void demo(void)
 {
      Wrapper w = decorate(&test);
      w();
 }

为什么要游览?好吧,仔细看一下特定的一行:

 void(*m_f)(void);

是的,有一个成员变量! Python实际上在内部做了类似的事情。

C的“问题”是您无法定义自己的函数调用运算符。只有本地人。因此,最大的问题是:函数指针存放在哪里?

您可以有一个结构,存储函数指针(类似于C ++解决方案),并将该指针传递给您自己的函数,以模拟函数调用运算符。实际上,C ++解决方案也没有做任何其他事情,仅是所有这些都隐藏在语法糖之后!

等效的C解决方案可能看起来像这样:

struct Wrapper
{
    void(*m_f)(void);
};

void executeDecorated(Wrapper w)
{
    printf("before\n");
    w.m_f();
    printf("after\n");
}

void demo(void)
{
    Wrapper w = { &someFunction };
    executeDecorated(w);
    /* do whatever else ... */
    executeDecorated(w);
}

这可能是您可以在C语言中获得的最接近的字母(除此之外,您可能会找到更好的名称)。

[如果具有单独的结构来存储函数指针会为您带来足够的好处,或者如果您只想直接传递函数指针(executeDecorated(&someFunction),假设函数已适当调整,则由您决定...

© www.soinside.com 2019 - 2024. All rights reserved.