C语言 存储类型关键字详解
今天我们重点说下auto,register,typedef,extern,和static。
让我们进入今天的学习吧!(今天也要加油哦)
1. auto(自动变量)
auto作为比较老的关键字,在C语言中使用的有限,简单说下语法吧。
auto:它很宽宏大量的,你就当它不存在吧,在缺省的情况下所有局部变量都是 auto 的。auto被叫做自动变量,就是变量空间自动申请释放,就是自动变量。
2 . static(静态变量)
static修饰的变量时,放在了静态数据区。
在上上篇博客中很详细说了,就不在赘述了。
static常考点
3.register(寄存器变量)
3.1 register语法
这个关键字请求编译器尽可能的将变量存在 CPU 内部寄存器中而不是通过内
存寻址访问以提高效率。注意是尽可能,不是绝对。你想想,一个 CPU 的寄存器也就那么几个或几十个,你要是定义了很多很多 register 变量,没有那么多的寄存器让register用。
3.2 寄存器变量可以取地址吗?
各位读者大人,想一个问题,那么可以对寄存器变量进行取地址操作吗?
例 1:
register a = 10;printf("%p\n", &a); //error C2103 : 寄存器变量上的“&”return 0;
这个例子就证明了,register变量不可被取地址,为什么不可以被取地址呢?
因为地址是内存相关的概念,你要取地址也要在内存上取吧,不在内存怎么取地址呢?
举个例子帮助理解下: 这就像一个人开车闯红灯要扣6分,但是人家就没有驾照你咋扣分呢?
3.3什么情况下使用register修饰变量的?
1.局部变量,(全局变量会占据寄存器)
2.不会被写入的(一旦写入,就要返回内存,然后再被检测)
3.被高频读写的(高频读写的放入寄存器中,会更容易的让CPU拿到)
3.4 register的变量的细节
寄存器变量是可以被赋值的。
例 2:
int main(){register a = 10;a = 100;printf("%d\n", a);//100return 0;}
寄存器变量的默认数据类型是int
也可以定义其他类型
例 3:
int main(){register char a = 10;a = 100;printf("%d\n", a);//a的类型是 charreturn 0;}
4.extern(外部存储变量)
4.1 extern作用
extern变量称为外部存储变量。extern声明了程序中将要用到但尚未定义的外部变量。通常,在C语言中extern主要负责的再头文件中的全局变量的声明,函数的声明。
4.2 extern的注意事项
首先extern声明外部符号的,在头文件中声明函数和全局变量的。
例 4:
extern int a;extern void fan();
那么再声明时可以初始化吗?
首先声明并非定义,定义时开辟的有空间,而声明中没有空间,所以声明不可以初始化。
声明时可以省略extern吗?
语法上不管是变量还是函数,不加extern好像都不会出错,但是就变量而言定义不初始化和声明是一样的写法
例 5:
int a;//声明int a;//定义但不初始化
没有注释,各位读者能分清楚声明和初始化吗?我想不能吧。所以在声明变量时,必须要带上extern。
那么函数呢,是不是可以不带extern呢?
例 6:
void fan();//声明void fan()//定义
从直观上是看可以看出来的,以分号结束的是声明,但是还是推荐大家声明函数时也带上extern。
声明可以多次吗?
可以多次声明,但是不可以多次定义。
举个例子: 你买彩票中奖了,你可以说很多次,但是就彩票中奖来说,你只中了一次,同理,声明可以多次,但定义只有一次。
5.typedef(特殊的存储类型)
5.1 typedef解释
typedef 的真正意思是给一个已经存在的数据类型(注意:是类型不是变量)取一个别名,而非定义一个新的数据类型。
5.2 typedef的使用
5.2.1 对结构体进行typedef
下面是结构体进行重命名之后的类型查看,来进一步判断是否typedef创建了新的类型。
例 7:
struct str//定义结构体{int a;};typedef struct str _str;//对结构体进行重命名int main(){struct str ret = { 0 };//创建结构体变量_str val = { 0 };//用typedef定义类型创建变量struct str * p = &val;//把typedef的变量地址存进结构体指针中return 0;}
调试查看类型可以看出类型是一样的。
5.2.2 对数组进行typedef
例 8:
typedef int a[10];//定义一个类型 int[10] 名字是aint main(){int b[10] = { 0 };//定义一个数组,数组类型是 int[10]a c = { 0 };//用a定义一个数组,数组类型是areturn 0;}
调试,查看类型,看出,a和b数组类型一样。
5.2.3 typedef对unsigned int重命名。
例9 :
typedef unsigned int _int;int main(){unsigned int a = 0;_int b = 0;return 0;}
调试看出,a,b类型一样
综上所述,可以看出typedef只是换了个名字,但是最终类型不变,有种换汤不换药的感觉。
5.3 typedef 和 define做比较
看个例子加深下理解
例 10:
typedef int* ptr_t;int main(){ptr_t a, b;//没初始化,不推荐大家写,只做研究return 0;}
这里看出typedef定义两者的类型是一样的。
例 10:
#define PTR_T int*int main(){PTR_T a, b;//不推荐这样写,只做研究return 0;}
define定义的可以看出不是一个类型,a是int*的,b是默认的int型。
得出结论
define 是定义一个宏来进行替换。
而typedef是把一个变量的名字换了。
6.总结存储类型关键字
这些存储类型关键字,上述也都说过了,他们或多或少的对一些变量或者函数的说呢过命周期和作用域,以及变量开辟空间相关,还有一个比较特殊的关键字typedef也归结到了存储类型关键字了。
重点来了
这些存储类型关键字不可以同时修饰一个变量
这是不可以的,数据只有一个存储类型,一个以上出现是不可以的。
下期预告
下期讲下volatile和sizeof,各位看官明天见
都看到这里了,给个三连吧