StoreType
概述
存储类型指示编译器以何种方式使用变量,它定义程序中变量/函数的范围(可见性)和生命周期。
数据类型用于声明不同类型的变量或函数,变量的类型决定了变量存储占用的空间和变量存储的格式。
存储类型包括以下几种:
- auto
- static
- const
- register
- extern
- volatile
auto
auto 存储类型是所有局部变量默认的存储类。
它声明的是在函数中的局部变量,它的生命周期在函数内。
程序动态分配存储空间,所谓动态是指在调用该函数时给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。
该类局部变量称为自动变量,其数据存储在动态存储区。
static
static 指示编译器在程序的生命周期内保持局部变量的存在,而不需要在每次它进入和离开作用域时进行创建和销毁。函数之间调用时,已创建的 static 变量的值不会被重置。
static 修饰符也可以应用于全局变量。当 static 修饰全局变量时,会使变量的作用域限制在声明它的文件内。
全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中。
#include <stdio.h>
void func1(void);/*函数声明*/
static int count=10;/*全局变量,static 是默认的*/
int main(){
while (count--) {
func1();
}
return 0;
}
void func1(void){
/* 'thingy'是'func1'的局部变量,它只初始化一次。
* 每次调用函数 'func1'时'thingy' 值不会被重置。
*/
static int thingy=5;
thingy++;
printf(" thingy 为 %d , count 为 %d\n", thingy, count);
}
const
只读变量
const 存储类型限制一个变量为只读变量,产生静态作用。
const 推出的初始目的,正是为了取代预编译指令,消除它的缺点,同时继承它的优点:
- 定义const只读变量,具有不可变性;
- 相较于宏定义来说,便于进行类型检查,消除隐患;
- 保护被修饰的只读变量,增强程序的健壮性
- 节省空间,宏定义给出的是立即数,因此在内存中有多份拷贝,const给出的对应内存地址,因此只产生一次内存分配;
- 编译期间确定值,效率更高。(宏定义确定值在预编译期)
只读变量与常量
常量是只读的,它被编译器放在内存中的只读区域,不能够修改。常量在声明的时候必须赋值;
只读变量是在内存的堆区中申请空间来存放变量的值,被编译器显式地限制不能被修改。只读变量可以在使用时再赋值。
对于C语言来说,在声明数组的时候必须用常量来初始化数组,不能用只读变量。常量与只读变量虽然都只读,且值不能修改,但它们在类型上不能混为一谈。
只读限定范围
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printValandAddr(const char * p){
printf("%d\n",p);
printf("%s\n",p);
}
int main()
{
typedef char * pStr;
const char *p1 ="string";
const pStr p2 ="string";
char * const p3=(char *)malloc(sizeof(char)*10);
strcpy(p3,"string");//若要改变指针指向的值,必须为指针赋字符串变量,需用strcpy函数
printValandAddr(p1);
p1++;//正确
printValandAddr(p1);
printValandAddr(p2);
*p2='a';//语法正确,但执行该句会使程序出错,因为字符串在常量区,报core dump
printValandAddr(p2);
printValandAddr(p3);
*p3='a';//正确
printValandAddr(p3);
}
const 使用的基本形式:const type m;
限定类型为type的变量m不可变。
- 替换基本形式中的type为
char
,m为*p1
,替换后可看作const char *p1;
,限定*p1
不可变,但p1
是可变的; - 替换基本形式中的type为
pStr
,m为p2
,替换后可看作const (char*) p2;
(实际无此语法),限定p2
不可变,但*p2
是可变的; - 可变是语法上可变,修改后可能执行会使程序出错。本例中“string”是字面量,在常量区,改不了。
const与指针混用的判断原则:沿着*号划一条线,
- 如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向的变量为常量;
- 如果const位于*的右侧,则const就是用来修饰指针本身,即指针本身是常量。
另外注意:对于const (char *) ;
来说,因为char *
是一个整体,相当于一个类型(如 char),因此,这是限定指针是const。
extern
extern 存储类型用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。
当使用 extern 时,对于未初始化的变量,会把变量名指向一个之前定义过的存储位置。即:要么初始化该变量,要么该变量已经在其他地方定义。
当有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
register
register 存储类型用于将局部变量的值直接存放在CPU的寄存器中。该类型变量叫寄存器变量,用关键字 register 声明。即该存储类型的目的是优化速度,提高执行效率。
一般地,register可存放整型,仅部分机器可存放浮点数。
一般情况下,变量的值是存放在内存中的。当程序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到运算器中。经过运算器进行运算,如果需要存数,再从运算器将数送到内存存放。如果有一些变量使用频繁,则为存取变量的值要花不少时间。
volatile
volatile 存储类型提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。即该存储类型的目的是保持原子操作,保证变量最新。