C语言中的变量有自己的属性,在定义变量的时候可以加上“属性”关键字,“属性”关键字指明了变量的特有意义。
- 加关键字语法:直接在类型前加关键字
property type var_name - 示例:
int main(){
auto char i;
register int j;
static long k;
extern double m;
return 0;
}
1、auto 关键字
- auto是C语言中局部变量的默认属性
- auto 表明将被修饰的变量存储在栈上
- 编译器,默认所有的局部变量都是 auto
示例:
void f(){
int i; // 局部变量默认属性为 auto
auto int j; // 显示声明 auto 属性
}
2、register 关键字
- register 关键字指明将局部变量存储在寄存器中
- register 只是请求寄存器变量,但不一定请求成功(寄存器数量有限)
- register 变量必须是 CPU 寄存器可以接受的值
- 不能用 & 运算符获取 register 变量的地址
示例:
#include<stdio.h>
//register int g_v; // error,全局变量不能为register
int main(){
register char var;
//printf("0X%08x", &var); //error,不能对register取地址
return 0;
}
说明:register 说明变量存储在寄存器中,根本就不在内存中,当然不能用取地址符取内存地址了。
为什么请求不一定成功呢,因为寄存器数量是有限的,当没有寄存器可用时,请求就是不成功的。
全局变量的声明周期从程序开始到程序结束,如果声明为 register 变量,就一直占用寄存器,这不合理,所以 C 语言就规定全局变量不能声明为 register 类型
既然寄存器这么麻烦,还要有 register 关键字呢,因为寄存器操作比内存操作要快很多,为了兼顾速度,可以将有些变量放在寄存器中。
3、static 关键字
- static 关键字指明变量的“静态”属性
- static 修饰的局部变量存储在程序静态区
- static 关键字同时具有“作用于限定符”的意义
- static 修饰的全局变量、函数作用域只在声明的文件中
例子:
#include<stdio.h>
int g_v; // 全局变量,程序的任意地方均能访问
static int g_vs; // 静态局部变量,只有在当前文件中可以访问
int main(){
int var; //局部变量,在栈上分配空间
static int svar; //静态局部变量,在静态存储区分配空间,作用域在main函数中
return 0;
}
实验分析:auto,register,static 对比
//5-1.c
#include<stdio.h>
int f1(){
int r = 0;
r++;
return r;
}
int f2(){
static int r = 0;
r++;
return r;
}
int main(){
auto int i = 0;
static int k = 0;
register int j = 0;
printf("%p\n", &i);
printf("%p\n", &k);
//printf("%p\n", &j); // error,不能对寄存器变量取地址
for (i = 0; i < 5; i++){
printf("%d\n", f1());
}
for (i = 0; i < 5; i++){
printf("%d\n", f2());
}
return 0;
}
可以看到 i 和 k 地址空间并不连续,差距较大,也说明 i 存储在栈中,k 存储在静态存储区。
f1() 中变量 r 为局部变量,每次进入函数 f1() 都会进行初始化。f2() 中静态变量 r 只初始化一次。
4、extern 关键字
1、extern 用于声明“外部”定义的变量和函数
- extern 变量在文件中的其他地方分配空间
- extern 函数在文件其他地方定义
2、extern 用于告诉编译器用 C 方式编译
- C++ 编译器和一些变种 C 编译器默认会按自己的方式编译函数和变量,通过 extern 关键可以命令编译器“以 C 方式进行编译”。
extern "C"{ // 按照C的规则编译
int f(int a, int b){
return a + b;
}
}
实验分析:
1、案例分析
//5-2.c
#include<stdio.h>
int main(){
printf("%d\n", i);
}
int i = 3;
上面的代码编译之后结果如下:
编译结果显示变量 i 未定义,因为在打印 i 的时候没有找到 i 的定义
2、程序修改
将上面的代码更改如下,在 main 函数之前用 extern int i; 声明,表示变量 i 在别处有定义,这样编译最终可以找到 i 的定义。这样就可以通过编译。更改后的代码如下:
//5-2.c
#include<stdio.h>
extern int i;
int main(){
printf("%d\n", i);
}
int i = 3;
3、extern 出现在其他文件中
当然变量 i 的定义也可能出现在其他文件中,直接看程序
//5-2.c
#include<stdio.h>
extern int i;
int main(){
printf("%d\n", i);
}
//g.c
int i = 3;
编译运行结果如下:
程序编译到 printf("%d\n", i); 时,由于前面声明了 i 是 extern 属性的,这里就先使用,在文件 g.c 中找到了变量 i 的定义。
5、小结
1、auto 变量存储在程序的栈中,默认属性
2、static 变量 存储在程序的静态区中
3、register 变量请求存储在 CPU 寄存器中
4、extern 变量在文件的其他地方分配空间
5、extern 能够指示编译器按照标准 C 方式编译程序