【C语言进阶剖析】5、变量属性

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 方式编译程序

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值