返回指向C中嵌套函数的函数指针

时间:2020-03-05 18:46:42  来源:igfitidea点击:

正如标题所指出的那样,我正在尝试声明一个嵌套函数并返回指向该函数的指针。我希望此函数"不"返回一个新的函数指针,该指针将返回对原始函数的求反。

这是我所拥有的:

someType not( someType original ) {
    int isNot( ListEntry* entry ) {
        return !original( entry );
    }

    someType resultFunc = calloc( 1024, 1 );
    memcpy( resultFunc, &isNot, 1024 );

    return resultFunc;
}

someType定义为:

typedef int(*someType)(ListEntry* entry)

解决方案

回答

我正在使用GCC。

我们可以使用以下标志打开嵌套函数:

-fnested-functions

当我们编译时。

回答

我也从未听说过C中的嵌套函数,但是如果gcc支持它,那么它将无法按我们期望的方式工作。我们只是简单地复制isNot的机器指令,并且在调用" not"时将不包括" original"的实际值。

我们应该使用C ++类来实现一个函数对象,该对象存储一个指针,该指针可以使用" original"的值进行初始化,并从" not"返回该类的实例。

回答

史蒂夫,我们对C函数的思维模式完全错误。

someType resultFunc = calloc( 1024, 1 );
memcpy( resultFunc, &isNot, 1024 );

从代码片段中,我可以推测我们认为可以将函数的已编译代码复制到一块内存中,然后再使用它。这种东西闻起来像Lisp一样,除非在Lisp中,我们也不会那样做。

实际上,当我们说"&isNot"时,我们将获得一个指向函数的指针。复制指针指向的内存会适得其反,因为在将可执行文件加载到内存时,内存已初始化,并且不会更改。在任何情况下,编写someFunc()都会导致核心转储,因为无法执行someFunc的堆内存,这可以保护我们免受各种病毒的侵害。

我们似乎期望在C中实现闭包。根本不存在该实现。与Lisp,Perl或者Ruby不同,一旦退出该框架,C就无法保留该框架的元素。即使在某些编译器中允许使用嵌套函数,我相信我们也不能从这些函数内部引用非全局变量。闭包的关闭对象确实是存储状态并实现operator()的C ++对象,但这是一种完全不同的方法,我们仍然必须手动执行操作。

更新:这是GCC文档的相关部分。查找"但是,只有在包含功能(在此示例中为hack)没有退出的情况下,此技术才有效。"

回答

我们将无法以所需的方式执行此操作。我们有两种选择。

我们可以使用宏:

#define FN_NOT(F) !F
#define notSomeFunc FN_NOT(someFunc)
...
x = notSomeFunc(entry);

但是我怀疑我们希望能够将取反的函数传递给其他带有函数指针的函数,这样就无法正常工作。

我们可以更改界面以接受一些额外的信息,例如

struct closure {
  void *env;
  int (*f)(struct closure* extra, ListEntry*);
};

static int isNot(struct closure* extra, ListEntry *entry) {
  someType original = extra->env;
  return !original(entry);
}

struct closure not(someType original) {
   closure rv;
   rv.env = original;
   rv.f = &isNot;
   return rv;
}

然后像这样使用它:

struct closure inverse_fn;
inverse_fn = not( &fn );
if( inverse_fn.f(&inverse_fn, entry) ) {
    ...
}

我们还可以尝试其他方法,例如运行时的JITing函数,但是这些技术将取决于平台和体系结构。这个解决方案很尴尬,但是纯C语言并且可移植。