为什么编译器将GCC中的嵌套函数(GNU扩展)的地址视为“非常数”?

问题描述 投票:3回答:1

GNU C编译器包含一个很好的C语言扩展,称为Nested Functions。但是,在某些方面文档尚不清楚。例如,它说

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

如果您尝试在包含函数退出后通过嵌套函数的地址调用嵌套函数,则所有地狱都会崩溃。

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

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

因此,一方面,如果您在包含函数退出之后调用嵌套函数,则“所有事情都会崩溃”,但是前面的几句话说,在某些情况下,这样做是可以的。] >

我想这是指“超出范围的事物”表示自动变量,因此特别值得重构的是

static int f() { ... }

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

进入

int outer() {
    int f() { ... } // f does not refer to outer's local variables
    ... // some use of f
}

[如果模块中除了f功能之外没有其他outer用途,即使假设outer功能以某种方式泄漏了f的地址也超出了它自己的范围。

但是,我很惊讶地发现以下代码没有编译

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

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

    return 0;
}

[抱怨initializer element is not constant(即nested_function)。

此限制是否有任何原因? (我无法想象一个函数的地址是非恒定的,即使它是嵌套的)

GNU C编译器对C语言进行了很好的扩展,称为嵌套函数。但是,在某些方面文档尚不清楚。例如,它说可以调用...

c gcc gnu nested-function static-initialization
1个回答
0
投票

[在当前的GCC实现中,仅在优化期间才省略了嵌套函数的不必要的静态链指针。它没有反映在类型系统中(与不绑定任何内容的C ++ lambda不同)。如果不进行优化,则编译器必须在堆栈上创建一个蹦床,因此在这种情况下,函数地址实际上是非恒定的。

© www.soinside.com 2019 - 2024. All rights reserved.