我们知道,变量是有数据类型的,通过数据类型我们知道这个变量将在内存中占用多少内存,计算机如何对该数据类型进行操作。

除此之外,变量还有存储类别

存储类别就是是变量在内存中的存储区域,它可以使常量区全局数据区栈区

常量区全局数据区的内存在程序启动时就已经由操作系统分配好,占用的空间固定,程序运行期间不再改变,程序运行结束后才由操作系统释放;它可以存放全局变量静态变量一般常量字符串常量

栈区的内存在程序运行期间由系统根据需要来分配(使用到变量才分配内存;如果定义了变量但没有执行到该代码,也不会分配内存),占用的空间实时改变,使用完毕后立即释放,不必等到程序运行结束;它可以存放局部变量函数参数等。

我们可以使用关键字来控制变量的存储类别(存储区域),共有4个关键字,如下:

  • auto(自动的)
  • static(静态的)
  • register(寄存器的)
  • extern(外部的)

auto

auto是“自动”的意思,在C语言中,亦可以认为是“默认”之意,也就是说,定义变量时使不使用auto修饰变量都是一样的,所有变量默认都是使用auto修饰,也因此我们一般很少使用。

int i=10auto int i=10表达的是同样一个意思,效果是一样的。

static

static的意思是指静态的。而对于使用static关键字修饰的变量,无论它是全局变量还是局部变量,它都是静态变量,都会被存储在静态数据区——当然,全局变量本来就存储在静态数据区,即使不加 static。

静态数据区的数据在程序启动时就会初始化,直到程序运行结束;对于代码块中的静态局部变量,即使代码块执行结束,也不会销毁。

注意:静态数据区的变量只能初始化(定义)一次,以后只能改变它的值,不能再被初始化,即使有这样的语句,也无效。

register

一般情况下,变量的值是存储在内存中的,CPU 每次使用数据都要从内存中读取。

register修饰变量,使用该变量时就不必访问内存,直接从寄存器中读取,大大提高程序的运行效率(寄存器快,但是数量有限,所以一般使用最频繁的变量定义为 register 的)。

关于寄存器变量有以下事项需要注意:

-
为寄存器变量分配寄存器是动态完成的,因此,只有局部变量和形式参数才能定义为寄存器变量。

-
局部静态变量不能定义为寄存器变量,因为一个变量只能声明为一种存储类别。

-
寄存器的长度一般和机器的字长一致,只有较短的类型如 int、char、short 等才适合定义为寄存器变量,诸如 double 等较大的类型,不推荐将其定义为寄存器类型。

-
CPU的寄存器数目有限,即使定义了寄存器变量,编译器可能并不真正为其分配寄存器,而是将其当做普通的auto变量来对待,为其分配栈内存。当然,有些优秀的编译器,能自动识别使用频繁的变量,如循环控制变量等,在有可用的寄存器时,即使没有使用 register 关键字,也自动为其分配寄存器,无须由程序员来指定。

extern

extern 是“外部”的意思,很多教材讲到,extern 用来声明一个外部(其他文件中)的变量或函数,也就是说,变量或函数的定义在其他文件中。

不过我认为这样讲不妥,因为除了定义在外部,定义在当前文件中也是正确的。例如,将 module.c 中的int m = 100;移动到 main.c 中的任意位置都是可以的。所以我认为,extern 是用来声明的,不管具体的定义是在当前文件内部还是外部,都是正确的。

(具体情况可以查看多文件编程)