【问题标题】:Return function pointer to a nested function in C将函数指针返回到 C 中的嵌套函数
【发布时间】:2010-09-07 14:50:14
【问题描述】:

正如标题所述,我正在尝试声明一个嵌套函数并返回一个指向该函数的指针。我希望这个函数“不”返回一个新的函数指针,它将返回原始函数的否定。

这是我所拥有的:

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)

【问题讨论】:

    标签: c pointers nested


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 感谢您的链接,我最喜欢的一句话是“如果您在包含函数退出后尝试通过其地址调用嵌套函数,那么一切都会崩溃。”
    【解决方案2】:

    你无法以你想要的方式做到这一点。您有几个备选方案。

    您可以使用宏:

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

    【讨论】:

      【解决方案3】:

      我正在使用 GCC。

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

      -fnested-functions
      

      当你编译时。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          猜你喜欢
          • 2020-04-29
          • 2015-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多