将函数定义为static
可以将其隐藏在其他翻译单元中,这有助于提供封装。
helper_file.c
int f1(int); /* prototype */
static int f2(int); /* prototype */
int f1(int foo) {
return f2(foo); /* ok, f2 is in the same translation unit */
/* (basically same .c file) as f1 */
}
int f2(int foo) {
return 42 + foo;
}
main.c:
int f1(int); /* prototype */
int f2(int); /* prototype */
int main(void) {
f1(10); /* ok, f1 is visible to the linker */
f2(12); /* nope, f2 is not visible to the linker */
return 0;
}
#include <helper_file.c>
吗?我认为那样会使它成为一个单一的翻译单元... - Atcoldgcc -std=c99 -pedantic -Wall -Wextra main.c helper_file.c
。函数的原型在两个源文件中都存在(不需要头文件)。链接器将解析这些函数。 - pmgstatic
时,链接器即使没有原型也可以找到它。缺少原型会防止编译器检查返回和参数类型,但不会阻止其发出调用该函数的代码。 - pmgpmg关于封装的观点是正确的;除了隐藏函数不被其他翻译单元调用(或者更确切地说,正因为此),将函数设为static
还可以在编译器进行优化时提供性能优势。
因为static
函数不能从当前翻译单元之外的任何地方调用(除非代码采用其地址的指针),所以编译器控制所有进入它的调用点。
这意味着它可以使用非标准的ABI,完全内联它,或执行任何数量的其他优化,而对于具有外部链接的函数可能不可能实现这些优化。
static
关键字用于C语言中的编译文件(.c文件,而不是.h文件),这样该函数只存在于该文件中。
通常,在创建一个函数时,编译器会生成一些垃圾代码,以便链接器可以使用它们将函数调用链接到该函数。如果使用了static关键字,则同一文件中的其他函数可以调用此函数(因为可以直接访问,无需借助链接器),而链接器没有提供任何信息让其他文件访问该函数。
看了上面的帖子,我想给出一个更明确的答案:
假设我们的main.c
文件长这样:
#include "header.h"
int main(void) {
FunctionInHeader();
}
现在考虑三种情况:
案例 1: 我们的"header.h"文件如下所示:因此,总之:
static keyword prevents the code defining a function to be linked,
when that function is defined in another translation unit than where it is called.
C程序员使用static属性来隐藏模块内的变量和函数声明,就像您在Java和C++中使用public和private声明一样。 C源文件扮演模块的角色。任何使用static属性声明的全局变量或函数都是私有的,只能由该模块访问。同样,任何未使用static属性声明的全局变量或函数都是公共的,可以被任何其他模块访问。在可能的情况下,使用static属性保护您的变量和函数是良好的编程实践。
pmg的回答非常有说服力。如果您想了解静态声明在对象级别上是如何工作的,那么以下信息可能对您很有帮助。
我重用了pmg编写的同一程序,并将其编译成.so(共享对象)文件。
以下内容是将.so文件转储为人类可读格式后的结果:
0000000000000675 f1: f1函数的地址
000000000000068c f2: f2(静态)函数的地址
注意函数地址的差异,这意味着某些事情。对于使用不同地址声明的函数,它可以非常明显地表示f2位于非常远或对象文件的不同段中。
链接器使用称为PLT(过程链接表)和GOT(全局偏移表)的东西来理解它们可以访问的符号链接到哪里。
现在暂时认为GOT和PLT神奇地绑定了所有地址,动态部分保存了链接器可见的所有这些函数的信息。
转储.so文件的动态部分后,我们得到了一堆条目,但只对f1和f2函数感兴趣。
动态部分仅保存了f1函数的地址为0000000000000675,而没有保存f2的地址!
Num: Value Size Type Bind Vis Ndx Name
9: 0000000000000675 23 FUNC GLOBAL DEFAULT 11 f1
就是这样!从中可以清楚地看出,由于f2函数不在.so文件的动态部分中,因此链接器将无法找到它。
当需要限制对某些函数的访问时,我们会在定义和声明函数时使用 static 关键字。
/* file ab.c */
static void function1(void)
{
puts("function1 called");
}
And store the following code in another file ab1.c
/* file ab1.c */
int main(void)
{
function1();
getchar();
return 0;
}
/* in this code, we'll get a "Undefined reference to function1".Because function 1 is declared static in file ab.c and can't be used in ab1.c */