C语言中的高阶函数
是否有一种“正确”的方法来实现C中的高阶函数 我很好奇这里的可移植性和语法正确性,以及是否有不止一种方法的优点和缺点 编辑: 我想知道如何创建高阶函数的原因是,我编写了一个系统,将PyObject列表(调用python脚本时得到的列表)转换为包含相同数据但不依赖python.h库的C结构列表。所以我的计划是有一个函数,它遍历一个pythonic列表,对列表中的每个项目调用一个函数,并将结果放入一个列表中,然后返回 这基本上是我的计划:C语言中的高阶函数,c,functional-programming,higher-order-functions,C,Functional Programming,Higher Order Functions,是否有一种“正确”的方法来实现C中的高阶函数 我很好奇这里的可移植性和语法正确性,以及是否有不止一种方法的优点和缺点 编辑: 我想知道如何创建高阶函数的原因是,我编写了一个系统,将PyObject列表(调用python脚本时得到的列表)转换为包含相同数据但不依赖python.h库的C结构列表。所以我的计划是有一个函数,它遍历一个pythonic列表,对列表中的每个项目调用一个函数,并将结果放入一个列表中,然后返回 这基本上是我的计划: typedef gpointer (converter_fu
typedef gpointer (converter_func_type)(PyObject *)
gpointer converter_function(PyObject *obj)
{
// do som stuff and return a struct cast into a gpointer (which is a void *)
}
GList *pylist_to_clist(PyObject *obj, converter_func_type f)
{
GList *some_glist;
for each item in obj
{
some_glist = g_list_append(some_glist, f(item));
}
return some_glist;
}
void some_function_that_executes_a_python_script(void)
{
PyObject *result = python stuff that returns a list;
GList *clist = pylist_to_clist(result, converter_function);
}
为了澄清这个问题:我想知道如何在更安全、更正确的C语言中实现这一点。我真的很想保持高阶函数的风格,但如果不赞成这种做法,我非常感谢用其他方法实现这一点。如果你想创建高阶函数,不要使用C语言。有C语言解决你的问题。他们可能不优雅,或者你意识到他们可能更优雅 [编辑]我建议实现这一点的唯一方法是使用脚本语言。其他人对这件事大声疾呼。因此,我将用以下内容替换该建议:[/Edit] 你想达到什么目标?如果您想模拟闭包,请使用支持闭包的语言(您可以通过库绑定到Ruby、lua、javascript等)。如果您想使用回调,函数指针是可以的。函数指针结合了C语言中最危险的区域(指针和弱类型系统),所以要小心。函数指针声明读起来也不有趣
您会发现一些C库使用函数指针,因为它们必须这样做。如果你在写一个库,也许你也需要使用它们。如果您只是在自己的代码中使用它们,那么您可能不会使用C语言。您使用的是lisp、scheme、ruby或。。。尝试用C语言编写。学习C语言。在C语言中,这实际上只是通过函数指针来完成的,函数指针既痛苦又不适合这种类型的东西(这就是它们痛苦的部分原因)。块(或闭包,根据非苹果公司的说法)在这方面非常棒。它们是用gcc-4.x或其他什么东西编译的,还有icc之类的东西,但不管你要找的是什么。不幸的是,我似乎在网上找不到任何好的教程,但我只想说它的工作原理如下:
void iterate(char *str, int count, (^block)(str *)){
for(int i = 0; i < count; i++){
block(list[i]);
}
}
main() {
char str[20];
iterate(str, 20, ^(char c){
printf("%c ", c);
});
int accum = 0;
iterate(someList, 20, ^(char c){
accum += c;
iterate(str, 20, ^(char c){
printf("%c ", c);
});
});
}
void iterate(char*str,int count,(^block)(str*)){
for(int i=0;i
显然,这段代码毫无意义,但它会打印字符串(str)中的每个字符,中间有一个空格,然后将所有字符相加到accum中,每次都会再次打印字符列表
希望这有帮助。顺便说一句,块在Mac OS X Snow Leopard api-s中非常明显,我相信在即将推出的C++0x标准中也有,所以它们并不特别。实际上,任何有趣的高阶函数应用程序都需要闭包,在C语言中,这需要手动定义和填充结构函数参数的繁琐且容易出错的例行程序。从技术上讲,高阶函数只是获取或返回函数的函数。所以像qsort这样的东西已经是高阶的了 如果你指的是更像函数语言中的lambda函数(这是高阶函数真正有用的地方),那么这些函数就更难了,而且在当前的标准C中无法自然完成。它们只是不属于该语言的一部分。苹果的blocks扩展是最好的选择。它只在GCC(和LLVM的C编译器)中工作,但它们确实很有用。希望这样的事情会流行起来。以下是一些相关资源:
- (参考了一些苹果特有的技术,也提到了Objective-C,但核心块是其C扩展的一部分)
在直C中很难做到。C++中更可能(参见或Boost和库)。最后,它负责在闭包中捕获函数所依赖的所有变量。
在C中实现高阶函数的一个大问题是,要做任何非平凡的事情,都需要闭包,闭包是函数指针,它通过包含它们可以访问的局部变量的数据结构进行扩展。由于闭包背后的整个思想是捕获局部变量并将其与函数指针一起传递,因此如果没有编译器支持,就很难做到这一点。即使有编译器支持,也很难不进行垃圾收集,因为变量可能存在于其作用域之外,因此很难确定何时释放它们。如果您喜欢在纯C中执行此操作,则需要记住包含从函子调用方传递上下文指针的选项(高阶函数)传递给传入的函数。这可以让您模拟足够多的闭包,使事情变得足够容易。指针指向的是什么…好吧,这取决于您,但它应该是functor API中的void*
(或它的许多别名之一,例如GLib世界中的gpointer
,或Tcl C API中的ClientData
)
[编辑]:要使用/改编您的示例:
typedef gpointer (converter_func_type)(gpointer,PyObject *)
gpointer converter_function(gpointer context_ptr,PyObject *obj)
{
int *number_of_calls_ptr = context_ptr;
*number_of_calls_ptr++;
// do som stuff and return a struct cast into a gpointer (which is a void *)
}
GList *pylist_to_clist(PyObject *obj, converter_func_type f, gpointer context_ptr)
{
GList *some_glist;
for each item in obj
{
some_glist = g_list_append(some_glist, f(context_ptr,item));
}
return some_glist;
}
void some_function_that_executes_a_python_script(void)
{
int number_of_calls = 0;
PyObject *result = python stuff that returns a list;
GList *clist = pylist_to_clist(result, converter_function, &number_of_calls);
// Now number_of_calls has how often converter_function was called...
}
这是一个简单的例子,说明了如何实现它,但它应该为您指明方向。这是对以下问题的回答:如何在C中编写函数,此处重定向 您可以创建数据结构来实现列表数据类型。 该结构可以包含函数指针
#include<stdlib.h>
#include<malloc.h>
typedef (*fun)();
typedef struct funList { fun car; struct funList *cdr;} *funList;
const funList nil = NULL;
int null(funList fs){ return nil==fs; }
fun car(funList fs)
{
if(!null(fs)) return fs->car;
else
{
fprintf(stderr,"error:can't car(nil) line:%d\n",__LINE__);
exit(1);
}
}
funList cdr(funList ls)
{ if(!null(ls)) return ls->cdr;
else
{
fprintf(stderr,"error:can't cdr(nil) line:%d\n",__LINE__);
exit(1);
}
}
funList cons(fun f, funList fs)
{ funList ls;
ls=(funList) malloc(sizeof(struct funList));
if(NULL==ls)
{
fprintf(stderr,"error:can't alloc mem for cons(...) line:%d\n",__LINE__);
exit(1);
}
ls->car=f;
ls->cdr=fs;
return ls;
}
它是如何工作的一个例子。我们使用(f g h)作为短
type_2 comp(funList fs, type_1 x)
{
return (null(fs)) ? x : car(fs)(comp(cdr(fs),x));
}
comp((f g h),x)
f(comp((g h),x))
f(g(comp((h),x)))
f(g(h(comp(nil,x))))
f(g(h(x)))
comp :: ([a -> a],a) -> a
typedef void (*fun)();
typedef (*fun)();