C语言中的static与extern关键字详解
C语言中的static与extern关键字详解
在讲解 static 与 extern 关键字之前,要先了解两个重要概念:作用域和生命周期。
作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效(可用)的,而限定这个名字的可用性的代码范围就是这个名字的作用域。
通俗的说,一个变量在哪里可以使用,哪里就是它的作用域。
1.局部变量的作用域就是变量所在的局部范围。
2.全局变量的作用域是整个工程(项目)。
生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段。
1.局部变量的生命周期是:进入作用域变量创建,生命周期开始,出作用域生命周期结束。
2.全局变量的生命周期是:整个程序的生命周期。
标题
了解了以上概念之后,接下来我们将正式开始 static 和 extern 关键字的学习。
在C语言中,**static**
和**extern**
是两个非常重要的关键字,它们用于控制变量和函数的链接属性和生命周期。下面我将详细解释这两个关键字:
1.static 关键字
**static**
关键字可以用来修饰变量和函数,它有以下几个用途:
局部静态变量:
• 当**static**
用于函数内部的局部变量时,它会改变变量的生命周期。没有static
的局部变量在函数调用结束后会被销毁,而加了**static**
的局部变量会保持其值,直到程序结束。
• 例如:
void func()
{
static int count = 0; // 局部静态变量
count++;
printf("%d\n", count);
}
每次调用**func**
时,**count**
的值都会累加。
结论:static修饰局部变量改变了变量的生命周期,生命周期改变的本质是改变了变量的存储类型,本来一个局部变量是存储在内存的栈区的,但是被 static 修饰后存储到了静态区。存储在静态区的变量和全局变量是⼀样的,生命周期就和程序的生命周期⼀样了,只有程序结束,变量才销毁,内存才回收。但是作用域是不变的。
全局静态变量:
• 当**static**
用于全局变量时,它会限制变量的链接属性,使得变量只在定义它的文件内可见,即具有文件内链接(file scope linkage),而不是外部链接(external linkage)。
• 例如:
// file1.c
static int global_var = 10; // 只在 file1.c 可见
// file2.c
extern int global_var; // 错误:无法访问,因为 global_var 只在 file1.c 可见
全局变量默认是具有外部链接属性的,可以在适当的声明后跨文件使用。
不过一旦被static修饰,就使得这个全局变量的外部链接属性变成内部链接属性。在外部的源文件中就无法直接使用了,只能在自己所在的 源文件 中使用。 相当于改变了全局变量的作用域,但是没有改变其生命周期。
使用建议:如果一个全局变量,只想在所在的源文件内部使用,不想被其他文件发现,就可以使用static修饰。
静态函数:
正常使用来自外部的函数时,只需要进行正确的声明便可正常使用。
• 当**static**
用于函数时,与修饰全局静态变量同理,它会限制函数的链接属性,使得函数只在定义它的文件内可见,从而不能在其他文件中正常的链接使用了。
• 例如:
// file1.c
static void func()
{
// ...
}
// file2.c
void func(); // 错误:无法访问,因为 func 只在 file1.c 可见
使用建议:一个函数只想在所在的源文件内部使用,不想被其他的源文件使用,就可以使用 static 修饰。
2.extern 关键字
**extern**
关键字用于声明全局变量或函数(外部符号),它有以下几个用途:
声明全局变量:
• **extern**
用于在多个文件中共享全局变量。它告诉编译器该变量在其他地方定义。
• 例如:
// file1.c
int global_var = 10; // 定义全局变量
// file2.c
extern int global_var; // 声明全局变量,告诉编译器在其他地方定义
printf("%d\n", global_var); // 可以访问 global_var
声明函数:
• **extern**
也用于在多个文件中共享函数。如果一个函数在一个文件中定义,并在其他文件中使用,那么在其他文件中需要用**extern**
来声明这个函数。
• 例如:
// file1.c
void func()
{
// ...
}
// file2.c
extern void func(); // 声明 func 函数,告诉编译器在其他地方定义
func(); // 可以调用 func 函数
3.总结
• **static**
用于控制变量和函数的生命周期和链接属性,使其具有文件内链接。
• **extern**
用于在多个文件中共享全局变量和函数,使其具有外部链接。
如果一个变量或函数同时被声明为 static 和 extern ,那么 static 的链接属性会覆盖 extern 的链接属性,这意味着该变量或函数将只在定义它的文件内部可见,即使它被声明为 extern 。这种组合通常用于头文件中,以防止同一个头文件被多次包含时造成重复定义的问题。
这两个关键字在C语言中非常重要,正确使用它们可以有效地管理程序的内存和链接属性。