c - C中静态函数的优先级

标签 c function static linkage

假设您有一个带有静态函数 Foo 的文件 File1.c,并且该函数是在 File1.c 中调用的。此外,在另一个文件 (File2.c) 中,您有另一个非静态的 Foo 函数。我知道静态函数在声明它的文件之外是不可见的,实际上对于链接器来说是不可见的。

但这是否意味着 File1.c 中 Foo 函数的内部调用总是在编译期间解决?

是否存在 File1.c 中的 Foo 调用可以链接到 File2.c 的全局 Foo 函数的情况?

最佳答案

总结

一旦你在一个翻译单元中定义了一个静态函数foofoo 将在翻译单元的其余部分引用该函数,除了它可以被隐藏翻译单元的一部分名为 foo 的非函数(例如对象或类型定义)。它不会链接到名为 foo 的外部函数。

通过修改下面解释的声明,一个标识符在理论上可以引用来自另一个翻译单元的一个函数,在这个翻译单元中一个static声明之后的同名函数.不幸的是,由于 C 2018 6.2.2 7,该行为未由 C 标准定义:

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

这意味着您不能单独依赖 C 标准来确保此行为,但 C 实现可以将其定义为扩展。

详情

C 的范围和链接规则回答了这些问题。

假设在 File1.c 中我们有一个函数的静态定义:

static int foo(int x) { return x*x; }

由于标识符 foo 是在任何函数之外声明的,因此它具有文件范围 (C 2018 6.2.1 4)。这意味着标识符 foo 是可见的,并为 File1.c 的其余部分指定此函数定义。此外,由于使用了 static,它具有内部链接 (6.2.2 3)。

范围有一个异常(exception)。对于其他范围内的范围,例如在文件内定义函数的 block { … } 或 block 内的 block ,相同标识符的声明可以隐藏外部声明。因此,让我们考虑在 block 内重新声明 foo

为了引用在 File1.c 之外定义的 foo,我们需要用外部链接声明 foo,这样这个新的 foo 可以链接到外部定义的 foo。有没有办法在 C 中做到这一点?

如果我们尝试在 block 内声明 extern int foo(int x);,则适用 6.2.2 4:

For an identifier declared with the storage-class specifier extern in a scope in which a prior declaration of that identifier is visible, if the prior declaration specifies internal or external linkage, the linkage of the identifier at the later declaration is the same as the linkage specified at the prior declaration.

所以这个声明只会重新声明相同的 foo

如果我们在没有 extern 的情况下声明它,使用 int foo(int x);,6.2.2 5 适用:

If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern.

所以,似乎我们不能声明一个有或没有 extern 的不同的 foo。但是,等等,我们还有一个技巧。我们可以通过使用没有链接的声明隐藏它来使指定内部或外部链接的先前声明不可见。要获得没有链接的声明,我们可以在没有 extern 的情况下声明一个对象(而不是函数):

#include <stdio.h>

static int foo(int x) { return x*x; }

void bar(void)
{
    int foo; // Not used except to hide the function foo.
    {
        extern int foo(int x);
        printf("%d\n", foo(3));
    }
}

因为 extern int foo(int x); 出现的地方,之前声明的带有内部链接的 foo 是不可见的,即 6.2.2 中的第一个条件 4上面引用的不适用,6.2.2 4 的其余部分适用:

If no prior declaration is visible, or if the prior declaration specifies no linkage, then the identifier has external linkage.

这是“合法的”C 代码。不幸的是,它未被 6.2.2 7 定义:

If, within a translation unit, the same identifier appears with both internal and external linkage, the behavior is undefined.

关于c - C中静态函数的优先级,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56133854/

相关文章:

c - pthread_cond_wait() 实际上是如何工作的?

c - 在 C 中使用八进制转义序列

php - Fat-Free-Framework 全局变量和函数

c++ - CMake 是否需要静态库(例如 ZLIB)?

c - C中的套接字编程(客户端服务器示例)

function - 是否可以使用通用函数在元组中获取元组的第二个元素?

javascript - forEach 中箭头函数内的三元运算符

java - 在 java 18 版本中不使用 main 方法时我没有收到任何错误

c# - 如何将项目添加到静态属性类型列表?

c - 使用 c 重命名和移动目录中的文件