【问题标题】:Why is the address of a nested function (GNU extension) in GCC considered "not constant" by the compiler?为什么编译器认为 GCC 中嵌套函数(GNU 扩展)的地址“不是常量”?
【发布时间】:2020-06-18 06:20:33
【问题描述】:

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
}

如果模块中除了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;
}

投诉initializer element is not constant(即nested_function)。

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

【问题讨论】:

  • 第一段说的是“名称范围之外”,而不是函数退出之后。也就是说,它可以作为参数传递给从包含函数中的另一个函数,该函数具有不同的范围并且看不到嵌套函数的名称。

标签: c gcc gnu nested-function static-initialization


【解决方案1】:

在当前的 GCC 实现中,嵌套函数的不必要的静态链指针仅在优化期间被省略。它不会反映在类型系统中(与不绑定任何东西的 C++ lambda 不同)。如果不进行优化,编译器必须在堆栈上创建一个蹦床,所以这种情况下函数地址实际上是非常量的。

【讨论】:

    猜你喜欢
    • 2016-03-28
    • 2010-10-27
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-14
    相关资源
    最近更新 更多