1

正如标题已经说明的那样,我试图声明一个嵌套函数并返回一个指向该函数的指针。我希望这个函数“不”返回一个新的函数指针,它将返回对原始函数的否定。

这是我所拥有的:

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)
4

4 回答 4

19

史蒂夫,你对什么是 C 函数有一个完全错误的心智模型。

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

从您的代码片段中,我可以推测您认为您可以将函数的编译代码复制到一块内存中,然后重用它。这种事情有 Lisp 的味道,但即使在 lisp 中你也不会那样做。

事实上,当你说“&isNot”时,你会得到一个指向函数的指针。复制指针指向的内存会适得其反——当您将可执行文件加载到内存中时,内存已被初始化,并且它没有改变。在任何情况下,编写 someFunc() 都会导致核心转储,因为无法执行 someFunc 的堆内存 - 这可以保护您免受各种病毒的侵害。

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

更新:这里是 GCC 文档的相关部分。寻找“但这种技术只有在包含函数(本例中为 hack)不退出时才有效。”

于 2008-09-02T21:47:07.957 回答
1

你将无法以你想要的方式做到这一点。您有几个替代选择。

您可以使用宏:

#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 且可移植。

于 2009-02-08T16:06:38.300 回答
0

我正在使用 GCC。

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

-fnested-functions

编译时。

于 2008-09-02T20:28:00.407 回答
0

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

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

于 2008-09-02T20:42:34.850 回答