变量作用域、存储类型以及extern关键字
本文主要介绍C语言的变量作用域、以及不同位置声明定义的变量的存储类型,extern关键字在声明函数和变量时的不同含义。
变量作用域
声明和定义的区别:
声明:可以多次,不分配存储空间,声明的位置决定作用域,主要用来向程序表明变量的类型和名称,给编译器提供引用标识。
定义:只能一次,给变量分配存储空间,还可以初始化变量,无声明的情况下决定作用域。
定义是一种特殊的声明,最重要的区别在于是否分配内存。在C语言中,所有变量在使用之前必须先声明,可以使用extern关键字来声明已经定义的变量,extern关键字会扩大变量的作用域。
// main.c #include <stdio.h> #include "test.h" extern int d; //声明变量d,变量d在test.c中定义,必须先声明才能使用,可以在main.c或test.h中进行声明,变量声明不会分配内存 int main(){ int a=100;//定义并声明变量a,并对变量a进行初始化,已分配内存 int b; //定义并声明变量b,不对变量b初始化,已分配内存 b=20; printf("a=%d,b=%d\n",a,b); fun_test(); printf("c=%d,d=%d\n",c,d); } //test.h extern int c; //声明变量c,不分配内存 extern void fun_test(); //声明函数fun_test //test.c #include <stdio.h> #include <unistd.h> int c=30; //定义并声明变量c,分配内存并初始化 int d; //定义并声明变量d,分配内存但未初始化 void fun_test(){ d=50; }
编译器可以确认4中不同类型的作用域:文件作用域、函数作用域、代码块作用域和原型作用域。标识符声明的位置决定它的作用域。
所有代码块之外声明的标识符都是具有文件作用域,它表示该变量从它的声明处到文件结尾都是可以访问的。
函数原型中声明的参数具有原型作用域。
在代码块开始位置声明的标识符具有代码块作用域。
goto
语句的标签具有函数作用域
链接属性
标识符的链接属性决定如何处理不同文件中出现的标识符。标识符的作用域与它的链接属性有关。链接属性可以改变标识符的作用域
链接属性一共有3个:
- external:多个文件中声明的同名标识符表示同一个实体。
- internal:单个文件中声明的同名标识符表示同一个实体。
- none: 声明的同名标识符代表独立不同实体。
只有具备文件作用域的标识符才能拥有external或internal链接属性,其他标识符都是none属性
默认情况下,具备文件作用域的标识符拥有external链接属性,也就是说该标识符可以跨文件访问。对于external属性的标识符,无论在不同文件中声明多少次,代表着都是同一个实体。
使用static关键字可以使得原先拥有external属性的标识符变为internal属性。static改变标识符链接属性,只对具有文件作用域的标识符有效。链接属性只能修改一次,一旦从external变为internal就无法变回。
存储类型
- 存储类型指的是存储变量的值的内存类型。
- 有三个地方可以存储变量值,分别是普通内存、运行时堆栈以及硬件寄存器。
- 代码块之外定义的变量存储在静态内存中。
- 代码块内部定义的变量存储在运行时堆栈中,该变量被定义为自动变量。
- 要是自动变量存储在硬件寄存器中,在定义变量时需要使用
register
关键字。 static
关键字用于代码块内部的变量时,会将变量的存储类型从自动变量改为静态变量。
static关键字
static
关键字有两个作用,一是改变标识符的链接属性,二是改变变量的存储类型。static
关键字作用于具有文件作用域的标识符时,会将标识符的链接属性从默认的external变为internal。static
关键字作用域具有代码块作用域的标识符时,会将标识符的存储类型从自动变量变为静态变量,即变量的存储位置从运行时堆栈改为静态内存。
extern关键字
extern
关键字将标识符的链接属性设置为external,可以在不同的源文件中访问。extern
关键字用来声明标识符时,表明该标识符定义在其他源文件中。(变量和函数)// main.c #include <stdio.h> #include "test.h" extern int d; //extern关键字用来声明变量d,表明变量d定义在其他文件中 int main(){ int a=100;//定义并声明变量a,并对变量a进行初始化,已分配内存 int b; //定义并声明变量b,不对变量b初始化,已分配内存 b=20; printf("a=%d,b=%d\n",a,b); fun_test(); printf("c=%d,d=%d\n",c,d); } //test.h //extern关键字用来声明变量c,表明变量c定义在其他源文件中。 extern int c; //extern关键字用来声明函数,表明函数定义在其他源文件中。 //因为函数的默认链接属性时extern,因此此处的extern只是显式的指明了链接属性。此处的extern可有可无。 extern void fun_test();
- 原文作者:生如夏花
- 原文链接:https://blduan.top/post/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80/c/%E5%8F%98%E9%87%8F%E4%BD%9C%E7%94%A8%E5%9F%9F%E5%AD%98%E5%82%A8%E7%B1%BB%E5%9E%8B%E4%BB%A5%E5%8F%8Aextern%E5%85%B3%E9%94%AE%E5%AD%97/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。