当前位置:  开发笔记 > 编程语言 > 正文

为什么C标准不支持嵌套函数?

如何解决《为什么C标准不支持嵌套函数?》经验,为你挑选了3个好方法。

在装配中实现它似乎不太难.

gcc还有一个标志(-fnested-functions)来启用它们.



1> 小智..:

事实证明,它们实际上并不是那么容易实现的.

内部函数是否可以访问包含范围的变量?如果没有,嵌套就没有意义了; 只是让它静态(以限制它所在的翻译单元的可见性)并添加一条评论说"这是一个仅由myfunc()使用的辅助函数".

但是,如果要访问包含范围的变量,则基本上强制它生成闭包(替代方法是限制使用嵌套函数可以做的事情足以使它们变得无用).我认为GCC实际上通过为包含函数的每次调用生成(在运行时)一个唯一的thunk来处理这个问题,该函数设置一个上下文指针,然后调用嵌套函数.这最终是一个相当Icky hack,以及一些完全合理的实现无法做到的事情(例如,在禁止执行可写内存的系统上 - 许多现代操作系统出于安全原因这样做).使其一般工作的唯一合理方法是强制所有函数指针携带隐藏的上下文参数,并且所有函数都接受它(因为在一般情况下,您不知道何时调用它是否是闭包或一个未公开的功能).出于技术和文化方面的原因,这在C语言中是不合适的,因此我们坚持使用显式上下文指针来伪造闭包而不是嵌套函数,或者使用具有所需基础结构的更高级语言.做得好.


在嵌套函数中实现上级变量访问的两种最常见的方法是"静态链接",其中每个函数都有一个指向其词法父级的堆栈帧的指针,以及"显示",它由一系列这样的指针组成.它基本上是一个链表而不是固定数组.你不需要完全封闭,除非你想在父节点退出后允许调用内部函数(例如,Pascal不允许).http://en.wikipedia.org/wiki/Call_stack#Lexically_nested_routines

2> Mark Rushako..:

我想引用 BDFL(Guido van Rossum)的话:

这是因为嵌套函数定义无法访问周围块的局部变量 - 只能访问包含模块的全局变量.这样做是为了查找全局变量不必走一串字典 - 就像在C中一样,只有两个嵌套的范围:locals和globals(除此之外,还有内置函数).因此,嵌套函数的用途有限.这是一个深思熟虑的决定,基于允许像Pascal和Algols这样的任意嵌套的语言的经验 - 具有太多嵌套作用域的代码与具有太多GOTO的代码一样可读.

重点是我的.

我相信他指的是Python中的嵌套作用域(正如David在评论中指出的那样,这是从1993年开始,Python现在支持完全嵌套的函数) - 但我认为该语句仍然适用.

它的另一部分可能是关闭.

如果你有像这样的C代码的函数:

(*int()) foo() {
    int x = 5;
    int bar() {
        x = x + 1;
        return x;
    }
    return &bar;
}

如果你bar在某种回调中使用,x会发生什么?这在许多较新的高级语言中都有明确定义,但是AFAIK没有明确定义的方法来跟踪xC - bar每次返回6,还是连续调用bar返回递增值?这可能会为C的相对简单的定义增加一个全新的复杂层.


据推测,如果您使用bar作为回调,则在包含它的函数返回后,您将使用局部变量(bar)的地址.如果bar是int(比如说),那么这应该是未定义的.
那是真的......嗯,我没有考虑过.但是C和Python在返回"本地"数组时也会做不同的事情(或者在python中返回列表).C将返回一个指向堆栈内存的指针,该堆栈内存不再明确定义; Python将返回一个全新的List.所以它们是不同的范例,我不确定它们是否具有可比性.
我只想指出有问题的报价超过10年:http://www.python.org/search/hypermail/python-1993/0343.html并且Python完全支持嵌套函数和嵌套作用域.

3> Christoph..:

有关潜在问题,请参阅C FAQ 20.24和GCC手册:

如果你试图在包含函数退出后通过其地址调用嵌套函数,那么所有的地狱都会破裂.如果您尝试在包含范围级别退出后调用它,并且如果它引用了一些不再在范围内的变量,那么您可能会很幸运,但冒风险并不明智.但是,如果嵌套函数没有引用超出范围的任何内容,那么您应该是安全的.

这并不比C标准的其他一些有问题的部分严重得多,所以我说原因主要是历史性的(C99 与K&R C特征并不完全不同).

在某些情况下,具有词法范围的嵌套函数可能会有用(考虑一个递归的内部函数,它不需要额外的堆栈空间用于外部作用域中的变量而不需要静态变量),但希望您可以信任编译器正确地内联这些函数,即具有单独函数的解决方案将更加冗长.

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有