为什么GCC中的嵌套函数(GNU扩展)的地址被认为是;“非常数”;由编译器完成?

为什么GCC中的嵌套函数(GNU扩展)的地址被认为是;“非常数”;由编译器完成?,c,gcc,gnu,nested-function,static-initialization,C,Gcc,Gnu,Nested Function,Static Initialization,GNUC编译器包含一个很好的C语言扩展,名为。 然而,文件在某些方面并不清楚。例如,它说 通过存储嵌套函数的地址或将地址传递给另一个函数[…],可以从其名称范围之外调用嵌套函数 如果您试图在包含函数退出后通过其地址调用嵌套函数,那么所有的麻烦都会发生 如果您试图在包含作用域级别退出后调用它,并且如果它引用了一些不再在作用域中的变量,那么您可能很幸运,但冒险是不明智的 但是,如果嵌套函数未引用超出范围的任何内容,则应该是安全的 一方面,它说,如果在包含函数退出后调用嵌套函数,“一切都会崩溃”,但前

GNUC编译器包含一个很好的C语言扩展,名为。 然而,文件在某些方面并不清楚。例如,它说

通过存储嵌套函数的地址或将地址传递给另一个函数[…],可以从其名称范围之外调用嵌套函数

如果您试图在包含函数退出后通过其地址调用嵌套函数,那么所有的麻烦都会发生

如果您试图在包含作用域级别退出后调用它,并且如果它引用了一些不再在作用域中的变量,那么您可能很幸运,但冒险是不明智的

但是,如果嵌套函数未引用超出范围的任何内容,则应该是安全的

一方面,它说,如果在包含函数退出后调用嵌套函数,“一切都会崩溃”,但前面几句话说,在某些情况下这样做是可以的

我认为“超出范围的东西”是指自动变量,所以重构应该是安全的

static int f() { ... }

int outer() {
    ... // some use of f
}
进入

如果模块中除了
outer
函数中的
f
没有其他用途,即使假定
outer
函数以某种方式泄漏
f
的地址超出了其自身的范围

然而,我惊讶地发现以下代码没有编译

int main(void) {
    void nested_function(void) {}

    static const struct { void (*function_pointer)(void); } s = {
        .function_pointer = nested_function
    };

    return 0;
}
投诉
初始值设定项元素不是常量
(即
嵌套函数


这种限制有什么原因吗?(我无法想象函数的地址是非常量的,即使它是嵌套的)

在当前的GCC实现中,嵌套函数不必要的静态链指针只在优化过程中被忽略。它没有反映在类型系统中(不像C++的lambda,它不绑定任何东西)。如果没有优化,编译器必须在堆栈上创建一个蹦床,因此在这种情况下函数地址实际上是非常量。

第一段提到的是“名称范围外”,而不是函数退出后的地址。也就是说,它可以作为参数从包含函数中传递给另一个函数,该函数具有不同的作用域,并且看不到嵌套函数的名称。
int main(void) {
    void nested_function(void) {}

    static const struct { void (*function_pointer)(void); } s = {
        .function_pointer = nested_function
    };

    return 0;
}