仓库源文站点原文


title: C 语言之变量存储类型与链接属性 layout: post categories: C语言 excerpt: C语言的变量存储类型与链接属性的区别分析

tags: 存储类型 链接属性 静态变量static extern 寄存器

C语言中一个重要的东西就是弄清申明变量的类型、作用域、存储类型、链接属性等,例如是整型还是浮点型,存储于普通内存还是堆栈或者寄存器,作用于全局还是局部,能否被其他文件 引用等。

链接属性

申明变量或函数时需要标识符,标识符的链接属性一共有三种:external(外部), internal(内部), none(无),external和internal常用,none表示无链接属性,该标识符的多个申明被当成独立不同的实体。

顾名思义,external表示能被其它源文件访问的变量或函数,internal则不能被其它源文件访问,并且缺省情况下代码块(block)外部的变量为external属性,也就是外部变量,代码块内部的变量为internal属性,即局部变量.

如果需要改变链接属性需要使用 externstatic 关键字,extern 是转化为external属性,static 是转化为internal属性。 举例说明:

#include<stdio.h>
int a = 1;              /* 这里是代码块外部,external 属性,缺省为"extern" */
extern int aa = 11;     /* 与上面效果一样 */
static int aaa = 111;   /* 这里申明的是 internal 属性,不能被其它源文件访问 */
void example()          /* 这里申明的 example() 函数也是external属性,能被其它源文件访问 */
{
    int b = 2;          /* 这里是代码块内部,internal 属性 */
    extern int bb = 22; /* 这里的意思是访问其它源文件的全局变量 */
}

注意上面指出的代码块内部和外部,定义的函数的花括号之外叫做代码块外部,之内叫做代码块内部。 代码块外部缺省为extern,并且代码块外部使用extern表示被其它源文件访问,代码块内部使用extern表示访问其它文件的外部变量。

存储类型

存储类型指申明的变量将被存储到什么地方去,并且与其存储周期有关,就是这个变量何时被创建,何时被销毁,保持多久。

存储类型有三种: 静态变量(static) ---> 存储于普通内存。 自动变量(auto) ---> 存储于堆栈。 寄存器变量(register) ---> 存储于寄存器。

静态变量

任何代码块之外定义的变量,总是处于静态内存中,无需使用 static 关键字,在程序运行之前创建,程序整个执行期间始终存在

自动变量

代码块内部申明的变量,并且缺省情况下都是(auto)类型,所以很少使用,存储于堆栈中,程序执行到申明变量处被创建,离开后被销毁,每次在堆栈中占据的内存位置都可能不同

寄存器变量

用于申明自动变量,即在代码块内部使用,使这类变量存储于寄存器中,寄存器中的变量比内存中的变量访问效率更高。 但是,如果有太多变量申明为 register ,只会选取前几个存储于寄存器中,其它处理为普通自动变量。

通常把使用频率最高的变量申明为寄存器变量,或者指针申明为寄存器变量,以提高效率。例如可以把函数的形参申明为寄存器变量(有可能它节省的时间空间开销抵不上复制这几个值的开销)。

综合举例
#include<stdio.h>
int a = 1;                  /* 静态变量(static),这里不能使用 register */
int main()
{
    int b = 2;              /* 自动变量,省略 auto */
    register int c = 3;     /* 寄存器变量(register) */
    int aaa(register int d) /* 申明函数形参为 register */
    static int e = 4;       /* 申明静态变量,和变量 b 一个属性 */ 
}
初始化

静态变量在不指定初始值的时候,初始化为 0; 自动变量是否初始化赋值,并无效率的改变(每次执行都要重新初始化),这也是它的优点:可以用任何“表达式”作为初始值。例如:

int add(int a)
{
    int b = a + 1;      /* 将表达式 a + 1 的值初始化给 b */
    return b;
}

注意

综合举例
#include<stdio.h>
int a = 1;             /* 链接属性为 external,缺省 extern */
static int b = 2;      /* 修改连接属性为静态变量,不能被其它源文件访问,依然为全局变量,存储于静态内存中 */
int main()
{
    int c = 3;         /* 自动变量,存储到堆栈 */
    static int d = 4;  /* 静态变量,存储到普通内存,依然不能被其它源文件访问 */
}