在装配中实现它似乎不太难.
gcc还有一个标志(-fnested-functions)来启用它们.
事实证明,它们实际上并不是那么容易实现的.
内部函数是否可以访问包含范围的变量?如果没有,嵌套就没有意义了; 只是让它静态(以限制它所在的翻译单元的可见性)并添加一条评论说"这是一个仅由myfunc()使用的辅助函数".
但是,如果要访问包含范围的变量,则基本上强制它生成闭包(替代方法是限制使用嵌套函数可以做的事情足以使它们变得无用).我认为GCC实际上通过为包含函数的每次调用生成(在运行时)一个唯一的thunk来处理这个问题,该函数设置一个上下文指针,然后调用嵌套函数.这最终是一个相当Icky hack,以及一些完全合理的实现无法做到的事情(例如,在禁止执行可写内存的系统上 - 许多现代操作系统出于安全原因这样做).使其一般工作的唯一合理方法是强制所有函数指针携带隐藏的上下文参数,并且所有函数都接受它(因为在一般情况下,您不知道何时调用它是否是闭包或一个未公开的功能).出于技术和文化方面的原因,这在C语言中是不合适的,因此我们坚持使用显式上下文指针来伪造闭包而不是嵌套函数,或者使用具有所需基础结构的更高级语言.做得好.
我想引用 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没有明确定义的方法来跟踪x
C - bar
每次返回6,还是连续调用bar
返回递增值?这可能会为C的相对简单的定义增加一个全新的复杂层.
有关潜在问题,请参阅C FAQ 20.24和GCC手册:
如果你试图在包含函数退出后通过其地址调用嵌套函数,那么所有的地狱都会破裂.如果您尝试在包含范围级别退出后调用它,并且如果它引用了一些不再在范围内的变量,那么您可能会很幸运,但冒风险并不明智.但是,如果嵌套函数没有引用超出范围的任何内容,那么您应该是安全的.
这并不比C标准的其他一些有问题的部分严重得多,所以我说原因主要是历史性的(C99 与K&R C特征并不完全不同).
在某些情况下,具有词法范围的嵌套函数可能会有用(考虑一个递归的内部函数,它不需要额外的堆栈空间用于外部作用域中的变量而不需要静态变量),但希望您可以信任编译器正确地内联这些函数,即具有单独函数的解决方案将更加冗长.