变量类型
常量是不可变的值,可以用宏来定义,比如 #define PI 3.14
变量的值是可以变化的,由于编程的不同需求,对变量有各种要求,
比如:变量的生命周期,变量的初始状态,变量的有效区域(作用域),变量的存储地和存储区域的大小。
为了满足这些不同的编程需求,C语言发明者设置了以下变量:
1 不同数据类型的变量。比如 char,int,float等。(变量在内存中占用地址大小由数据类型决定)
2 全局变量
3 局部变量
4 静态变量:包括静态全局变量和静态局部变量
5 寄存器变量
6 外部变量
C语言中,除了基本类型外,开发者可以通过typedef来定义自己需要的数据类型。比如:
typedef int INT;
typedef unsigned int UINT;
typedef struct student
{
char *name;
int age;
}STUDENT;
如果结构体student不用typedef重定义的话,定义结构体变量时:struct student stu1;
使用typedef重定义以后,我们只需要STUDENT stu1;即可。
1 全局变量。在函数外定义,可被所有函数使用。但是在多线程访问时,需要注意多线程安全问题。
2 局部变量。在函数内部声明。只有在函数执行时,局部变量才存在,函数执行完局部变量就消失。
3 静态变量。分配在内存中的数据段中,在C程序运行的整个过程中一直保留,静态变量可以定义成静态全局变量和静态局部变量。
①静态全局变量在程序的整个运行期间都存储且内存地址不会改变。
②静态局部变量只在声明它的函数内有效,且在下一次调用时还保留上次调用结束时的值(只初始化一次)。
4 寄存器变量。 寄存器变量存放在CPU的寄存器中,使用寄存器变量比内存变量操作速度快得多。
只有整型和字符型变量可以定义为寄存器变量。比如:
register int i;
register char c;
①由于CPU中寄存器有限,尽量减少使用寄存器的数量和占用时间,用完马上释放。
②寄存器变量不能定义为全局变量,也不能定义在结构体和类中。
③如果寄存器已经无可用资源,寄存器变量将转化为普通局部变量。
extern:
在大型程序中,会将一个大型的程序分成多个独立的模块和文件分别编译,然后统一链接在一起。为了解决全局变量和函数的共用问题,
引入了extern关键字。只需要在一个文件中定义全局变量和函数,在另一个文件中要用到这些变量和函数时,只需要将那个文件中的变量和
函数说明复制过来,然后在前面加上extern就可以。这样就等于告诉编译器,这些变量和函数已经在别的文件中定义。
变量的存储空间
代码和数据,都要加载到内存中,才能被运行和访问。X86系统中,内存的有效范围为4GB。
①高2GB内存地址为内核空间,用来存放内核的代码和数据
②低2GB为用户空间,运行进程的用户态代码,且低2GB的内存是进程私有空间,一个进程不能跨进程访问别的进程空间的用户态地址。
如图所示,程序在内存中分为如下几部分:
1 .text 代码段,这段是存放代码的
2 .rdata 只读数据段,不能修改,存放常量,字符常量,const常量。
3 .data 数据段 存放已经初始化好的全局变量和静态变量
4 .bss 存放未初始化的全局变量和静态变量
PS:.rdata,.data,.bss都是存放数据的段。.rdata段和.data段的值都在编译的时候就确定了,并且将值编译进了
可执行文件,经过反汇编就可以找到。已初始化的全局变量放在.data段,未初始化的变量放在bss段。
5 .stack 栈段,栈中存放普通的局部变量(非静态局部变量),形参,返回地址等。栈的大小有限制:
windows应用层栈大小默认为1MB;普通内核栈的大小是固定的,由系统根据CPU架构决定,X86系统上12KB,X64系统24KB,安腾系统32KB
Linux应用层栈大小默认为10MB,内核栈大小4KB或8KB
6 堆: 可以存放任意数据
综上:
①全局初始化变量存放在静态存储区的.data段
②全局未初始化变量存放在静态存储区的.bss段
③局部变量存放在栈
④全局静态变量和局部静态变量存放在静态存储区的.data段和.bss段
⑤常量存放在静态区的.rdata段。.rdata区域是只读内存,不能修改
⑥寄存器变量存放在寄存器中 (如果寄存器资源不够,还是放在内存中)
变量的作用域
变量的作用域指变量能在代码什么地方可以被访问到。
1 全局变量: 所有程序中的代码都能访问。
如果全局变量在一个源文件中定义,在另一个源文件中访问,需要用extern关键字导入。多线程访问全局变量注意安全问题
2 静态全局变量: 在同一个源文件中可以访问,不同源文件不可访问,也不能用extern来导入。
3 局部变量:只能在函数内部访问
4 静态局部变量:只能函数内部访问
5 寄存器变量:只能在函数内部访问
变量的生命周期
变量的生命周期是指变量在程序运行期间的有效时间
1 全局变量:整个程序运行期间有效
2 静态全局变量:整个程序运行期间有效
3 局部变量:函数范围内或代码块范围内有效
4 静态局部变量:整个程序运行期间有效
5 寄存器变量:函数范围内或代码块范围内有效
习题:分析下列程序中每个变量的存储位置,作用域,与生命周期
int a = 0;
char *p1;
static int x = 10;
void main(void)
{
int b = 0;
char s[] = "123";
char *p2;
char *p3 = "hello, world";
static int c =0;
p1 = (char *)malloc(128);
p2 = (char *)malloc(256);
free(p1);
free(p2);
}
分析与解答:下面给出了上面各变量的类型,存储,作用域和生命周期的详细的归纳:
int a = 0; //全局初始化变量
char *p1; //全局未初始化变量
static int x = 10;//全局初始化静态变量
void main(void)
{
int b = 0; //局部变量
char s[] = "123"; //s局部变量,字符数组,用"123"字符串常量进行初始化
char *p2; //局部变量
char *p3 = "hello, world"; //p3局部变量,字符指针,指向"hello, world"字符串常量
static int c =0; //静态局部变量,已初始化
p1 = (char *)malloc(128); //p1,p2指向堆
p2 = (char *)malloc(256);
free(p1); //显示释放p1,p2指向的堆内存
free(p2);
}