C 存储类
存储类定义C程序中变量或者函数的范围(可见性)和生命周期.这些说明符放置在他们所修饰的类型之前,C中有四个可以使用的存储类.
1 auto 存储类
auto存储类是所有的局部变量默认的存储类,且auto只能用在函数内部,即只能用于修饰局部变量
{
int age;
auto int Mage;//本行代码在C++中会报错
}
auto在C++中已经更改了用法,详情可见另一篇文章C++中auto关键字的使用
auto int Mage;
本行代码在C++中报错如下
2 register存储类
register存储类用于定义存储在寄存器中而不是RAM中的局部变量
2.1什么情况下使用register
register修饰一个变量中,这意味着该变量将会频繁的被使用,编译器应该将其保存在CPU的寄存器中,用来加快存储速度.
即遇到频繁使用的变量时,为了加快存储速度,使用register修饰.
下面的例子可以看出不同类型的变量所花费的世家不同
#include <stdio.h>
#include <time.h>
#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("寄存器变量用时: %ld 秒\n", stop - start);
//time(time_t *seconds) 返回自纪元 Epoch(1970-01-01 00:00:00 UTC)起经过的时间,以秒为单位。如果 seconds 不为空,则返回值也存储在变量 seconds 中。
time(&start);
for (x = 0; x < y; x++);
time(&stop);
printf("一般变量用时: %ld 秒\n", stop - start);
time(&start);
for (m = 0; m < n; m++);
time(&stop);
printf("全局变量用时: %ld 秒\n", stop - start);
return 0;
}
笔者电脑输出如下:
发现寄存器并不比一般变量用时短.原因见下.
2.2注意事项
-
register变量必须是能被CPU接受的类型,
这意味着register修饰的变量必须是一个单个的值,并且长度应该小于等于整型的长度.但是也有的机器的寄存器可以存放浮点数.
-
因为register可能不会保存在内存中,所以不能使用&来获取register修饰的变量的地址.
int main() { register int age = 22; cout << &age << endl; return 0; }
执行结果如下:
发现并没有报错,原因为许多编译程序会忽略register修饰符,因为他虽然完全合法,但是它仅仅是暗示而不是命令.1
-
只有局部变量和形式参数可以作为寄存器变量,其他(例如全局变量)不行.
在调用一个函数时占用一些寄存器以存放寄存器变量的值,函数调用结束后释放寄存器。此后,在调用另外一个函数时又可以利用这些寄存器来存放该函数的寄存器变量。
-
局部静态变量不能定义为寄存器变量
int main(){ register static int a,b,c; return 0; }
报错如下:
因为static也是一种存储类;
-
由于寄存器的数量有限(不同cpu的寄存器数目不同),不能定义任意多个寄存器变量,而且某些寄存器仅可以接受特定类型的数据(如指针和浮点数),因此register修饰符是否起作用在于运行的机器,多余的register修饰符都会被编译程序忽略
3 static 存储类
static存储类指示编译器在程序的生命周期内保持局部变量的存在,而不需要每次进入和离开作用域时进行创建和销毁,因此,使用static修饰的局部变量可以在函数调用之间保持局部变量的值.
static修饰符也可以使用于全局变量,当static修饰全局变量时,会使变量的作用域限制在声明他的文件内部,全局声明的static变量或者方法可以被任何函数或者方法调用,只要这些方法出现在跟static变量或者方法同一个文件中.
#include <stdio.h>
//函数声明
void func1(void);
//由static修饰的全局变量
static int count = 10;
int main(){
while(count--){
func1();
}
return 0;
}
void func1(void){
static int thingy = 5;
thingy++;
printf("thingy为%d,count为%d\n",thingy,count);
}
输出如下:
如果删除修饰thingy
变量的static
那么输出如下:
即发现,如果由static
修饰,那么局部变量不会在每次调用时被重新创建,即值不会被初始化为’6’,所以thingy
会有递增,而删除后,每次调用都会重新创建和销毁thingy
变量所以每次输出值都是’6’;
注意:虽然thingy
无static
修饰时,会多次创建和销毁,但是他的地址并不会改变.
#include <stdio.h>
//函数声明
void func1(void);
//由static修饰的全局变量
static int count = 10;
int main() {
while (count--) {
func1();
}
return 0;
}
void func1(void) {
int thingy = 5;
thingy++;
printf("thingy为%d,thingy地址为%d,count为%d\n", thingy, (int)&thingy, count);
}
输出如下:
4 extern 存储类
extern存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的,当使用extern时,对于无法初始化的变量,会把变量名指向之前一个定义过的存储位置.
当我们使用多个文件并且定义了一个可以在其他文件中使用的全局变量或者函数的时候,可以在其他文件中使用extern来得到已经定义的变量或者函数的引用,可以理解为,extern用来在另一个文件中声明一个全局变量或者函数.
extern通常用于当有两个或者多个文件共享相同的全局变量或者函数的时候.
以下是文件一的内容
#include <stdio.h>
int count;
extern void write_extern();
int main(){
count=5;
write_extern();
}
以下是文件二的内容
#include <stdio.h>
extern int count;
void write_extern(void){
printf("count is %d\n",count);
}
输出如下:
文件二中声明的count已经在文件一中被定义,所以他的值就是5,而函数在文件一中仅仅被声明,未被定义,在文件二中才被定义,但是可以看到函数正常执行,输出的值也是正常的.
注意:两个文件中,变量名和函数名应该都相等.
5 总结
关键字 | 介绍 |
---|---|
auto | 局部变量中的默认存储类,限定变量只能在函数内部使用 |
register | 代表了寄存器变量,不在内存中使用 |
static | 全局变量默认的储存类,表示变量在程序声明周期内可见 |
extern | 表示全局变量,即对程序内部所有文件可见 |
参考文章:
简述历史及原因
早期的C编译程序不会把变量保存在寄存器中,除非你命令它这样做,这时register修饰符是C语言的一种很有价值的补充。然而,随着编译程序设计技术的进步,在决定哪些变量应该被存到寄存器中时,现在的C编译环境能比程序员做出更好的决定。实际上,许多编译程序都会忽略register修饰符,因为尽管它完全合法,但它仅仅是暗示而不是命令。 ↩︎