我试图使用函数指针在C中实现类似Python的函数修饰器,但我得到了奇怪的分段错误错误。
思想是我们有一个装饰器函数,它有内部函数包装器。然后,装饰器将some_function作为参数,将其与其他代码一起放入包装器中,并返回包装器函数。
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
这是有趣的一点。如果我在包装器中声明一个变量,如下所示:
auto void wrapper()
{
int blah=5;
func();
func();
}
然后对分割故障进行修复。有人能解释一下为什么会这样吗?显然,我对指针做了一些错误,而且代码非常不稳定--似乎与主函数无关的添加将导致分段错误再次弹出。
发布于 2019-10-05 16:25:48
你允许我去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)
,假设函数经过了适当的调整),则由您来决定.
https://stackoverflow.com/questions/58252959
复制相似问题