今日听说某君批评 C 语言说它【输入一个参数返回一个函数】很困难。

例如在 Python 中,你可以

def addn(n):
def addx(x):
return n + x
return addx my_adder = addn(42)
print(my_adder(21))

标准 C 要实现这样的功能也不是不可以,这是一个闭包的功能,我们只要显式的把上下文抓住就可以了。

#include <stdio.h>

typedef struct Adder { int n; } Adder;

Adder addn(int n) {
Adder addn;
addn.n = n;
return addn;
} int apply(Adder addn, int x) { return addn.n + x; } int main() {
Adder add42 = addn(42);
printf("%d\n", apply(add42, 21)); return 0;
}

这样的写法未免过于复杂,而闭包是现代程序设计里面很常用到的一种结构,面对更复杂的上下文,为了模拟闭包,所要做的比一个 Adder 结构体要多得多。对于这样常用的结构,主流的 C 编译器,即 gcc 和 clang 都提供了 C 扩展来支持这样的功能。

在 clang 中,你可以这样写

#include <stdio.h>
#include <Block.h> int (^addn(int n))(int) {
__block int i = n; return Block_copy( ^(int x) {
return x + n;
});
} int main() {
int (^add42)(int) = addn(42);
printf("%d\n", add42(21)); return 0;
}

熟悉 Objective-C 的同学应该对 block 不陌生,这里 block 的类型名写起来比较麻烦,可以用 typedef int (^MyClosure)(int); 来定义更有可读性的类型名。

在 gcc 中,可以使用 nested functions 扩展

#include <stdio.h>

int (*addn(int n))(int) {
int addx(int x) {
return n + x;
} return addx;
} int main() {
int (*add42)(int) = addn(42);
printf("%d\n", add42(21)); return 0;
}

同样这里的函数指针也可以用 typedef 来定义一个可读的类型名。

这个问题在 C++ 中可以通过在类中重载括号运算符来实现。本质上是上面复杂代码所揭示出的捕获上下文并查看上下文信息的动作,现代语言为此封装了看起来像直接调用的简洁语法,使得代码更好写,更好读。

C 扩展对闭包特性的支持的更多相关文章

  1. 目前主流编译器对C++11特性的支持情况

    目前主流编译器对C++11特性的支持情况 1. GCC编译器(从编译器GCC4.8.X的版本完全支持) (1)目前C++11特性,之前成为C++0X特性,从GCC4.3的后续版本中逐步对C++11进行 ...

  2. 深入理解JavaScript的闭包特性如何给循环中的对象添加事件

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  3. 快速入门系列--WCF--08扩展与新特性

    最后一章将进行WCF扩展和新特性的学习,这部分内容有一定深度,有一个基本的了解即可,当需要自定义一个完整的SOA框架时,可以再进行细致的学习和实践. 服务端架构体系的构建主要包含接下来的几个要素:服务 ...

  4. Datagrid扩展方法onClickCell{easyui-datagrid-扩充-支持单元格编辑}

    //-----------------------------------------------------------------/******************************** ...

  5. 如何给循环中的对象添加事件--深入理解JavaScript的闭包特性

    初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...

  6. 深入理解JavaScript的闭包特性 如何给循环中的对象添加事件(转载)

    原文参考:http://blog.csdn.net/gaoshanwudi/article/details/7355794 初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数 ...

  7. JavaScript的闭包特性

    闭包是一个比较抽象的概念,尤其是对js新手来说.在这里,我就我个人的理解j简单谈一下: 闭包:官方解释是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部 ...

  8. 从匿名函数(闭包特性)到 PHP 设计模式之容器模式

    匿名函数(匿名函数) 匿名函数,也叫闭包函数,它允许临时创建一个没有指定名称的函数,常用作回调函数参数的值,也可以作为变量的值来使用.具体的使用见以下示例代码: /* 示例一:声明一个简单匿名函数,并 ...

  9. JavaScript快速检测浏览器对CSS3特性的支持情况

    项目中使用动画效果在IE9下不支持,所以写了个判断浏览器是否支持动画的函数,进而扩展到下面判断浏览器支持任一特定CSS3属性的函数. function supportAnimation(){ var ...

随机推荐

  1. 用户体验要素——产品系统设计方法

    用户体验已经成为了每个互联网人的口头词,特别是互联网产品经理或产品设计师. 的确,对于任何一个互联网产品而言,体验都是非常重要的. 但是具体的用户体验到底指的是哪些方面,界面,UI,还是交互,其中到底 ...

  2. 使用阿里云对docker拉取镜像加速

    使用docker的时候,总是需要去search镜像,使用国外的源下载太慢,还有诸多的限制,无意中发现可以使用阿里云进行加速,实测有用,废话少说,操作如下: 1.打开阿里云控制台,没有的可以用淘宝账号或 ...

  3. 01-Spring Security框架学习--入门(二)

    一.入门案例 Spring Security 自定义登录界面 通过之前的一节 01-Spring Security框架学习--入门(一)的简单演示,Spring security 使用框架自带的登录界 ...

  4. 映射&集合

    哈希函数 通过哈希表可以实现 O(1) 复杂度的查找. 哈希函数构造方法:设计好的哈希函数的两个基本原则,计算简单+分布均匀 1. 直接定址法 用key自身的某个线性函数来定址,f(key) = a* ...

  5. 【CodeForces - 1200C】Round Corridor (数论gcd)

    Round Corridor  Descriptions Amugae位于一个非常大的圆形走廊中.走廊由两个区域组成.内部区域等于nñ扇区,外部区域等于m米部门.在相同区域(内部或外部)的每对扇区之间 ...

  6. JavaScript 数组、字符串、Map、Set 方法整理

    在线阅读 https://www.kancloud.cn/chenmk/web-knowledges/1080519 数组 isArray():Array.isArray(value) 用于检测变量是 ...

  7. 谷歌hack

    0x00 网上搜集整理的一些可能会用到的Googlehack语法 0x01 intitle: 从网页标题中搜索指定的关键字,可专门用来搜索指定版本名称的各类 web 程序,也可用 allintitle ...

  8. SpringBoot整合Dubbo配合ZooKeeper注册中心

    安装ZooKeeper 我这里使用zookeeper作为服务注册中心,版本3.4.9,下载地址: http://mirrors.hust.edu.cn/apache/zookeeper/zookeep ...

  9. mybatis逆向工程maven版本idea工具

    基于springboot2版本 pom基本依赖 <parent> <groupId>org.springframework.boot</groupId> <a ...

  10. Hive 系列(七)—— Hive 常用 DML 操作

    一.加载文件数据到表 1.1 语法 LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION (p ...