pmg*_*pmg 210
使函数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;
}
Run Code Online (Sandbox Code Playgroud)
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;
}
Run Code Online (Sandbox Code Playgroud)
Ste*_*non 79
pmg是关于封装的点; 除了将函数隐藏在其他转换单元之外(或者更确切地说,因为它),使函数static也可以在存在编译器优化的情况下提供性能优势.
因为static无法从当前转换单元之外的任何位置调用函数(除非代码采用指向其地址的指针),否则编译器会控制所有调用点.
这意味着它可以自由地使用非标准ABI,完全内联,或执行任何其他优化,这些优化对于具有外部链接的函数可能是不可能的.
3Do*_*ons 28
staticC中的关键字用于编译文件(.c而不是.h),因此该函数仅存在于该文件中.
通常,当您创建一个函数时,编译器会生成链接器可以使用的cruft,以及将函数调用链接到该函数.如果使用static关键字,则同一文件中的其他函数可以调用此函数(因为它可以在不借助链接器的情况下完成),而链接器没有信息让其他文件访问该函数.
看看上面的帖子,我想指出一个细节.
假设我们的主文件("main.c")如下所示:
#include "header.h"
int main(void) {
FunctionInHeader();
}
Run Code Online (Sandbox Code Playgroud)
现在考虑三种情况:
案例1:我们的头文件("header.h")如下所示:
#include <stdio.h>
static void FunctionInHeader();
void FunctionInHeader() {
printf("Calling function inside header\n");
}
Run Code Online (Sandbox Code Playgroud)
然后在linux上执行以下命令:
gcc main.c header.h -o main
Run Code Online (Sandbox Code Playgroud)
会成功的!如果一个人跑了
./main
Run Code Online (Sandbox Code Playgroud)
输出将是
在标题内调用函数
这是静态函数应该打印的内容.
案例2:我们的头文件("header.h")如下所示:
static void FunctionInHeader();
Run Code Online (Sandbox Code Playgroud)
我们还有一个文件"header.c",如下所示:
#include <stdio.h>
#include "header.h"
void FunctionInHeader() {
printf("Calling function inside header\n");
}
Run Code Online (Sandbox Code Playgroud)
然后是以下命令
gcc main.c header.h header.c -o main
Run Code Online (Sandbox Code Playgroud)
会出错.
案例3:
与案例2类似,但现在我们的头文件("header.h")是:
void FunctionInHeader(); // keyword static removed
Run Code Online (Sandbox Code Playgroud)
然后,与情况2相同的命令将成功,并且进一步执行./main将给出预期结果.
所以从这些测试(在Acer x86机器上执行,Ubuntu OS)我做了一个假设
static关键字阻止在另一个文件中定义函数,而不是在声明它的位置.
如果我错了,请纠正我.
小智 5
C程序员使用static属性隐藏模块内的变量和函数声明,就像在Java和C++中使用公共声明和私有声明一样.C源文件扮演模块的角色.使用static属性声明的任何全局变量或函数对该模块都是私有的.类似地,没有静态属性声明的任何全局变量或函数都是公共的,并且可以由任何其他模块访问.使用静态属性尽可能保护变量和函数是一种很好的编程习惯.
pmg的回答很有说服力。如果您想知道静态声明如何在对象级别工作,那么下面的信息可能对您很有趣。我重用了由 pmg 编写的相同程序并将其编译成一个 .so(shared object) 文件
以下内容是在将 .so 文件转储为人类可读的内容之后
0000000000000675 f1 : f1 函数的地址
000000000000068c f2 : f2(staticc) 函数的地址
注意函数地址的不同,它意味着什么。对于使用不同 address 声明的函数,它可以很好地表示 f2 位于非常远的地方或位于目标文件的不同段中。
链接器使用称为 PLT(程序链接表)和 GOT(全局偏移表)的东西来理解他们有权链接到的符号。
现在想想 GOT 和 PLT 神奇地绑定了所有地址,一个动态部分保存了链接器可见的所有这些函数的信息。
在转储 .so 文件的动态部分后,我们得到了一堆条目,但只对f1和f2函数感兴趣。
动态部分仅保存地址0000000000000675处的f1函数的条目,而不保存f2 的条目!
Num:值大小类型绑定可视 Ndx 名称
9: 0000000000000675 23 FUNC GLOBAL DEFAULT 11 f1
Run Code Online (Sandbox Code Playgroud)
就是这样!。由此可见,链接器将无法成功找到f2函数,因为它不在 .so 文件的动态部分。
| 归档时间: |
|
| 查看次数: |
121997 次 |
| 最近记录: |