最近在学习 Operating System,作业需要使用 C 语言在一个 toy OS 中进行编程与学习。 在原始提供的源码中,发现有许多 static
和 extern
的关键字,故在此做一下总结与整理。
extern
首先来看一下 extern
。其最主要的作用就是可以引用工程的其他文件中定义的变量或函数。
假设有两个文件 foo1.c
和 foo2.c
:
foo1.c
_10int var;
foo2.c
_10extern int var;
最终生成可执行文件时,需要分别编译 compile 和链接 link:
_10gcc -c foo1.c_10gcc -c foo2.c_10gcc foo1.o foo2.o -o foo // link
在编译过程中,编译器只会为 foo2.c
中的 var 分配内存,在 foo1.c
中仅仅生成一个名为 var 的 symbol。而后在 link 过程中,链接器会将该 symbol 替换为 foo2.c
中的 var 的内存地址,从而达到指向同一变量的目的。
extern
的实际应用场景主要在编写库 library。打个比方,假设有名为 Mylib 的库,包含 Mylib.c
和 Mylib.h
。
MyLib.c:
_10int Variable;
MyLib.h:
_10extern int Variable;
main.c:
_10# include "MyLib.h"_10_10int main ( void )_10{_10 Variable = 10;_10 printf ( "%d\n", Variable ) ;_10 return 0;_10}
在。h 文件中使用 extern
来引用。c 库文件中定义的变量后,用户即可通过 include 头文件来使用库中的变量。
static
回到之前提到的例子,如果 foo2.c
中的 extern
去掉又会怎样呢。
对于未初始化的变量,GCC 会默认将它们视为同一个变量,效果与 extern
GCC 会报错:
_10/tmp/ccFN6SQZ.o: ( .data+0x0 ) : multiple definition of `var'_10/tmp/ccbc0T4O.o: ( .data+0x0 ) : first defined here
假设 foo1.c
与 foo2.c
分别来自于两个不同的库,如果用户想要同时 include 这两种库时,就会产生 multiple definition 的错误。作为库的开发者,有责任防止这种多重定义的情况的发生,因此需要用到 static。
static
保证了定义的变量和函数只存在该文件范围内,其他的文件无法 link 这些变量和函数,从而避免了多重定义的问题。
除此之外,定义在函数中 static
变量在函数被调用后可维持该变量的值。
来看一下下面的例子:
_18void foo ( )_18{_18 int a = 10;_18 static int sa = 10;_18_18 a += 5;_18 sa += 5;_18_18 printf ( "a = %d, sa = %d\n", a, sa ) ;_18}_18_18int main ( )_18{_18 int i;_18_18 for ( i = 0; i < 10; ++i )_18 foo ( ) ;_18}
这种情况下,main 函数调用 foo
函数,在 foo
执行完退出后,sa
变量仍然保持其退出前的值。当 foo
被在此调用的时候,sa
会在原来的基础上再加 5
。
当我们需用保留调用函数的某种状态而又不想创建全局变量时,这种方法就显得比较有用。然而,这种方法的滥用会导致程序的可读性和线程安全,所以需要谨慎使用。
在 C++中,static
还可用于 class 属性,在此不再赘述。