社区首页 >问答首页 >C中类似Python的函数装饰器

C中类似Python的函数装饰器
EN

Stack Overflow用户
提问于 2019-10-05 14:56:16
回答 1查看 543关注 0票数 0

我试图使用函数指针在C中实现类似Python的函数修饰器,但我得到了奇怪的分段错误错误。

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

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

代码语言:javascript
代码运行次数:0
复制
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中模拟相同类型的功能。

我试过这个

代码语言:javascript
代码运行次数:0
复制
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;
}

输出

代码语言:javascript
代码运行次数:0
复制
Hello
Segmentation fault

这是有趣的一点。如果我在包装器中声明一个变量,如下所示:

代码语言:javascript
代码运行次数:0
复制
  auto void wrapper()
  {
    int blah=5;
    func();
    func();
  }

然后对分割故障进行修复。有人能解释一下为什么会这样吗?显然,我对指针做了一些错误,而且代码非常不稳定--似乎与主函数无关的添加将导致分段错误再次弹出。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-10-05 16:25:48

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

代码语言:javascript
代码运行次数:0
复制
 struct Wrapper
 {
     /* this is what allows the struct to be called like a function: */
     void operator()(/* can define arbitrary parameters here */)
     { /* some implementation */ }
 };

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

代码语言:javascript
代码运行次数:0
复制
 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

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

代码语言:javascript
代码运行次数:0
复制
 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++代码可能如下所示:

代码语言:javascript
代码运行次数:0
复制
 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();
 }

为什么要去旅行?好吧,仔细看看一条具体的路线:

代码语言:javascript
代码运行次数:0
复制
 void(*m_f)(void);

是的,有一个成员变量!Python实际上在内部执行类似的操作。

C的“问题”是,您不能定义自己的函数调用操作符。只有土生土长。因此,最大的问题是:函数指针存储在哪里?

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

类似的C解决方案可能如下所示:

代码语言:javascript
代码运行次数:0
复制
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),假设函数经过了适当的调整),则由您来决定.

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58252959

复制
相关文章
js|jq获取兄弟节点,父节点,子节点
08.19自我总结 js|jq获取兄弟节点,父节点,子节点 一.js var parent = test.parentNode; // 父节点 var chils = test.childNodes; // 全部子节点 var first = test.firstChild; // 第一个子节点 var last = test.lastChile; // 最后一个子节点  var previous = test.previousSibling; // 上一个兄弟节点 var next = test.next
小小咸鱼YwY
2019/09/11
15.1K0
jquery 获取元素(父节点,子节点,兄弟节点)
1、jquery 获取元素(父节点,子节点,兄弟节点) $("#test1").parent(); // 父节点 $("#test1").parents(); // 全部父节点 $("#test1").parents(".mui-content"); $("#test").children(); // 全部子节点 $("#test").children("#test1"); $("#test").contents(); // 返回#test里面的所有内容,包括节点和文本 $("#test").content
biaoblog.cn 个人博客
2022/08/11
5.6K0
nvue获取节点信息
我们生活在阴沟里,但依然有人仰望星空。——王尔德 在nvue中我们获取节点信息就需要如下写法: <template> <view ref="list-parent" class="ruben"> <list> <cell><view>阿超</view></cell> </list> </view> </template> <script> const dom = weex.requireModule('dom'); export default { data() { return
阿超
2022/08/21
1.5K0
nvue获取节点信息
php获取所有节点的父节点和子节点
根据子节点获取所有的父节点以及父节点的父节点.. <?php $src = '[{"id":"1","name":"媒体(白名单)","pid":"0"},{"id":"2","name":"党媒公
黄啊码
2020/05/29
6.2K0
MySQL连接错误
ERROR 1045 (28000): Access denied for user’root’@’localhost’(using password:YES)
一点儿也不潇洒
2018/08/07
3.6K0
MySQL连接错误
xpath库详解xpath入门获取所有节点 //子节点 /父节点 ..属性匹配 @文本获取按序选择节点轴选择
python爬虫抓取网页内容,需要对html或xml结构的数据进行解析,如果用正则,单是写正则表达式就让很多望而生畏了。
章鱼喵
2018/09/26
25.2K0
xpath库详解xpath入门获取所有节点 //子节点 /父节点 ..属性匹配 @文本获取按序选择节点轴选择
XML获取当前节点信息
%XML.Node的以下字符串属性。提供关于当前节点的信息。 在所有情况下,如果没有当前节点,将抛出一个错误。
用户7741497
2022/07/05
1.6K0
【Debug】npm下载报错:npm ERR! code ETIMEDOUT npm ERR! syscall connect npm ERR! errno ETIMEDOUT
网络问题😶‍🌫️ npm的默认地址是国外的,在下载依赖时,由于网速问题可能会导致这样那样的错误~ # 查看自己的安装源 npm config get registry # 更换npm源为国内淘宝镜像 npm config set registry http://registry.npm.taobao.org/ # 或者国内npm官方镜像 npm config set registry http://registry.cnpmjs.org/ # ----- 还原npm源 ------ npm co
且陶陶
2023/04/12
4.4K0
【Debug】npm下载报错:npm ERR! code ETIMEDOUT npm ERR! syscall connect npm ERR! errno ETIMEDOUT
Java连接SqlServer错误
这次使用的是 SqlServer 数据库,之前并没有使用过,但是问题不大,我按照需求文档的步骤连接好 SqlServer 之后,启动 SpringBoot 项目,发现了一个报错,如下:
程序员Leo
2023/08/07
4900
Java连接SqlServer错误
qttreewidget详解_qtreewidget获取节点层级
1:通过findItems 过滤出符合条件的item 只是用于简单的过滤,复杂的效果不太好, 推荐第二种
全栈程序员站长
2022/11/15
2.8K0
qttreewidget详解_qtreewidget获取节点层级
inode节点--软硬连接和作用
一般情况下,文件名和inode号码是”一一对应”关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码。
陈不成i
2021/05/25
1.2K0
【JavaScript】获取对应的节点总结
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="dv"> <ul id="uu"> <li>第一个</li> <li>第二个</li>嘎嘎 <li id="three">第三个</li>哈哈 <li>第四个</li> <li>第五个</li> </ul> </div> <script
游魂
2018/06/08
1.4K0
vue是如何获取元素节点 ?
Js中:用document.getElement之类的语句来操作dom; vue:使用vue提供的api,用 ref 来获取节点;
青梅煮码
2023/01/16
2.8K0
SQL根据指定节点ID获取所有父级节点和子级节点
根据指定节点ID获取所有父节点 with temp as( select * from dbo.Category where Id=493 --表的主键ID union all select t.* from temp,dbo.Category t where temp.Pid=t.Id --父级ID=子级ID )select * from temp order by Level; [查询结果] 根据指定节点ID获取所有子节点 with temp as( select * from dbo.Category
段邵华
2019/08/01
6K0
获取DOM节点的方法汇总
我们都知道,当获得所有节点(如:getElementsByTagName)或者获得所有子元素(如:element.childNodes)时,实际上返回的是包含一些DOM节点的集合,这个集合要么是 HTMLCollection,要么是 NodeList,两者其实都是类数组的对象。
Chor
2019/11/07
4.3K0
JavaScript之怎样获取元素节点
JavaScript获取元素节点一共有三种方法,分别是通过元素ID、通过标签名字和通过类名字来获取; 1.通过元素ID属性的ID值来获得元素对象-getElementById() DOM提供了一个名为getElementById()的方法,这个方法将返回一个与括号里有着一样id值的元素节点对应的对象。他是document对象特有的函数,这个函数的参数只有一个,只能是你想要获得的元素的ID值,这个值必须放在单引号或者双引号里面。 注意:JavaScript语言区分字母大小写,所以在写getElementByI
郑小超.
2018/01/24
1.3K0
树形结构已知子节点获取子节点所有父节点——任意目录/树
JS 树形结构 根据子节点找到所有上级,比如element-tree,已知路由上的子结点id,如何回填的 展开目录树?
周陆军博客
2023/05/07
3.3K0
element tree 获取当前节点和其父级节点的数据
需求:树形菜单点击之后需要形成面包屑,所以需要当前节点和其父级节点的数据。记录一下解决方法,如下。
用户7741497
2022/03/06
2.7K0
MYSQL vs JAVA 连接错误
最近开发告诉我,他们在测试系统的时候,会经常有连接MYSQL的连接被踢掉。具体给我的解释是,JAVA的缓冲池连接MYSQL 保持连接,但再次使用的时候,报连接错误。
AustinDatabases
2019/07/12
3.9K0
MYSQL  vs JAVA 连接错误
java根据子节点获取它对应的所有父节点_java根据父节点查找子节点
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
全栈程序员站长
2022/10/01
6.9K0

相似问题

将ereg_replace转换为preg_replace

21

将此ereg_replace转换为preg_replace

19

将eregi转换为preg_match,将ereg_replace转换为preg_replace

18

将ereg_replace更改为preg_replace

10

在php中将ereg_replace转换为preg_replace

12
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档