(1)局部变量:局部变量也叫自动变量,它声明在函数开始,生存于栈,它的生命随着函数的返回而结束。
#include
int main(void)
{
auto int i = 9; //声明局部变量的关键字是 auto; 因可以省略,所以几乎没人使用
printf("%d\n", i);
getchar();
return 0;
}
(2)全局变量:全局变量声明在函数体外,一般应在函数前。每个函数都可以使用它,不过全局变量应尽量少用。
#include
void add(void);
void mul(void);
int gi = 3; //全局变量(声明在函数外)
int main(void)
{
printf("%d\n", gi); //输出的是 3
add();
printf("%d\n", gi); //输出的是 5
mul();
printf("%d\n", gi); //输出的是 10
getchar();
return 0;
}
void add(void) {
gi += 2;
}
void mul(void) {
gi *= 2;
}
全局变量会被初始化为空, 而局部变量在没有赋值前是一个垃圾值:
#include
int gi; //全局变量
int main(void)
{
int i; //局部变量
printf("%d, %d\n", gi, i);
getchar();
return 0;
}
当全局变量与局部变量重名时,使用的是局部变量:
#include
int a = 111, b = 222;
int main(void)
{
int a = 123;
printf("%d,%d\n", a, b); //输出的是 123,222
getchar();
return 0;
}
(1)静态生存周期(即全局变量的生存周期)
具有静态生存周期的所有对象,都是在程序开始执行之前就被事先创建和初始化。它们的寿命覆盖整个程序的执行过程。如在函数内定义了一个static变量,那第一次调用该函数后,该变量的值将会被保留,当第二次被调用时,该变量的值还是第一次调用结束时的值。
(2)自动生存周期(即局部变量的生存周期)
自动生存周期的对象的寿命由“对象定义所处在的大括号{}”决定。每次程序执行流进入一个语句块,此语句块自动生存周期的对象就会被创建一个新实例,同时被初始化。
(1)外部链接
表示在整个程序中(多个程序文件)是相同的函数或对象。常见的有,在函数体外声明的extern变量。
(2)内部链接
表示只在当前程序文件中是相同的函数或对象。其它程序文件不能对其进行访问。常见的有,在函数体外声明的static变量。
(3)无链接
一般声明在函数内部的auto、register变量、还有函数的参数,都是无链接。它的作用域是函数内部。
存储类型修饰符可以修改标识符的链接和对应对象的生存周期;标识符有链接,而非生命周期;对象有生存周期,而非链接;函数标识符只可用static、extern修饰,函数参数只可用register修饰。
(1)auto(对应自动生存周期)
auto修饰符只能用在函数内的对象声明中,即仅在语句块内使用。
声明中有auto修饰符的对象具有自动生存周期。
它们仅存在于被定义的当前执行代码块中,即局部变量在进入模块时生成,在退出模块时消亡。
定义局部变量的最常见的代码块是函数。 语言中包括了关键字auto,它可用于定义局部变量。但自从所有的非全局变量的缺省值假定为auto以来,auto就几乎很少使用了。
(2)static(对应静态生存周期)
如果是定义在函数外,那么该对象具有内部链接,其它程序文件不能对其访问。如果是定义在函数内,那么该对象具有无链接,函数外不能对其访问。
(注意:static变量初始化时,只能用常量)
用 static 关键字修饰的局部变量称为静态局部变量。
静态局部变量存值如同全局变量,区别在于它只属于拥有它的函数,它也和全局变量一样会被初始化为空。
#include
void fun1(void);
void fun2(void);
int main(void)
{
int i;
for (i = 0; i < 10; i++) fun1();
printf("---\n");
for (i = 0; i < 10; i++) fun2();
getchar();
return 0;
}
void fun1(void) {
int n = 0; //一般的局部变量
printf("%d\n", n++);
}
void fun2(void) {
static int n; //静态局部变量,会被初始化为空
printf("%d\n", n++);
}
用 static 关键字修饰的全局变量是静态全局变量,静态全局变量只能用于定义它的单元。
//譬如在 File1.c 里面定义了:
static int num = 99; /* 去掉前面的 static 其他单元才可以使用 */
//在 File2.c 里使用:
#include
extern int num;
int main(void)
{
printf("%d\n", num);
getchar();
return 0;
}
用静态变量记录函数被调用的次数:
#include
int fun(void);
int main(void)
{
int i;
for (i = 0; i < 10; i++) {
printf("函数被调用了 %2d 次;\n", fun());
}
getchar();
return 0;
}
int fun(void) {
static int n;
return ++n;
}
(3)const
(4)extern(对应静态生存周期)
extern 意为“外来的”。它的作用在于告诉编译器:这个变量或者函数的定义在别的地方,当遇到此变量或函数时应到其他模块中寻找其定义。
(PS:这个变量,它可能不存在于当前的文件中,但它肯定要存在于工程中的某一个源文件中或者一个Dll的输出中。)
#include
extern int g1;
int main(void)
{
extern int g2; //告诉编译器g2定义在其他地方
printf("%d,%d\n", g1,g2);
getchar();
return 0;
}
int g1 = 77;
int g2 = 88;
使用extern时,注意不能重复定义,否则编译报错,如:
程序文件一:
extern int a = 10; //编译警告,extern的变量最好不要初始化
程序文件二:
extern int a = 20; //重复定义,应改为extern int a;
(一般最好这样,如果需要初始化,可把extern修饰符去掉(但也不要重复定义),另外如果其它程序文件也需要用到该变量,可用extern来声明该变量。这样会比较清晰。)
另外,extern也可用来进行链接指定。
(5)volatile
(6)register(即寄存器变量,对应自动生存周期)
当声明对象有自动生存周期时,可以使用register修饰符。因此,register也只能用在函数内的声明中。
register修饰符暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中(而不是栈或堆),以加快其存储速度。然而,编译器不见得会这么做,因此效果一般般。了解一下就行,不建议使用。
#include
#include
#define TIME 1000000000
int m, n = TIME; //全局变量
int main(void)
{
time_t start, stop;
register int a, b = TIME; //寄存器变量
int x, y = TIME; //一般变量
time(&start);
for (a = 0; a < b; a++);
time(&stop);
printf("寄存器变量用时: %d 秒\n", stop - start);
time(&start);
for (x = 0; x < y; x++);
time(&stop);
printf("一般变量用时: %d 秒\n", stop - start);
time(&start);
for (m = 0; m < n; m++);
time(&stop);
printf("全局变量用时: %d 秒\n", stop - start);
getchar();
return 0;
}
使用register修饰符有几点限制:
首先,register变量必须是能被CPU所接受的类型。这通常意味着register变量必须是一个单个的值,并且长度应该小于或者等于整型的长度。不过,有些机器的寄存器也能存放浮点数。 其次,因为register变量有可能被存放到寄存器中而不是内存中,所以不能用“&”来获取register变量的地址。(7)缺省修饰符
函数内,与auto相同,函数外,与extern相同。
int func1(void); //func1具有外部链接
int a = 10; //a具有外部链接,静态生存周期
extern int b = 1; //b具有外部链接,静态生存周期。但编译会有警告extern变量不应初始化,同时也要注意是否会重复定义
static int c; //c具有内部链接,静态生存周期
static int e; //e具有内部链接,静态生存周期
static void func2(int d)
{
//func2具有内部链接;参数d具有无链接,自动生存周期
extern int a; //a与上面的a一样(同一变量),具有外部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明
int b = 2; //b具有无链接,自动生存同期。并且将上面声明的b隐藏起来
extern int c; //c与上面的c一样,维持内部链接,静态生存周期。注意这里的不会被默认初始为0,它只是个声明
//如果去掉了extern修饰符,就跟b类似了,无链接,自动生存周期,把上面声明的c隐藏起来
static int e; //e具有无链接,静态生存周期。并且将上面声明的e隐藏起来;初始化值为0
static int f; //f具有无链接,静态生存周期
}
相关链接参考:
http://developer.51cto.com/art/201105/261465.htm
http://apps.hi.baidu.com/share/detail/30353645
http://www.cnblogs.com/del/archive/2008/12/04/1347305.html