嵌入式—c语言变量范围及生命周期
1.局部变量和全局变量
变量分为局部变量和全局变量,因为有的变量只能在本程序中使用,而有的变量可以在其他函数中使用,这就是变量作用域问题。
1.1局部变量
定义:
只能在一定范围内使用的变量称为局部变量
例如:
只能在本函数中才能引用,其他函数是不能使用这些变量的;复合语句中定义的变量只能在该范围内使用,其余是不能使用的。
3种情况
(1)在函数的开头定义
(2)在函数内的复合语句内定义
(3)在函数的外部定义
例如:
//形式参数也是局部变量,变量a只在f1中有效,其他函数可以调用f1函数
//但不能直接引用f1函数的形参a
float f1(int a)
{
int b,c;
...
}
//不同函数可以使用相同的变量名,它们代表不同的对象,互不干扰;
//它们在内存中占不同的单元,不会混淆
char f2(int x,int y)
{
int b,c;
...
}
//主函数定义的m,n两个变量只能在主函数中有效
//主函数中也不能使用其他函数中定义的变量
int main()
{
int m,n;
....
{
int c;//只在此复合语句中有效,离开复合语句就无效,系统会把它占用的内存单元释放
c = a+b;
}
....
return 0;
}
1.2全局变量
定义:
在函数之外定义的变量称为外部变量,外部变量也称为是全局变量也称为是全称变量。
范围:
从定义变量的位置开始到本源文件结束
作用:
是增加函数键数据联系的渠道,由于同一文件中所有函数都能引用全局变量的值,因此如果在一个函数中改了全局变量的值,就会影响到其他函数中全局变量的值,相当于各个函数间有直接的传递通道。
由于函数的调用只能带回一个函数返回值,因此有时候可以利用全局变量来增加函数间的联系渠道,通过函数调用能得到一个以上的值。
注意:
一般在定义全局变量名的时候,通常第一个字母用大写表示
例如:定义全局变量
float Max = 0;Min = 0
//有一个一维数组,内放10个学生成绩,写一个函数,当主函数调用此函数后能求出平均分,最高分和最低分
#include<stdio.h>
float Max = 0;Min = 0;//定义全局变量
float average(float array[],int n);//函数的声明
int main()
{
float ave,score[10];//定义变量和数组
int i;
printf("please enter 10 score:\n");
for(i=0;i<10;i++)
{
scanf("%d",&score[i]);
}
//调用函数时,把实参数组score的首元素地址和整数10传递给了形参数组array和形参变量n;
//函数average的值是return语句带回的aver的值
ave=average(score,10);
printf("max=%6.2f\nmin=%6.2f\naverage=%6.2f\n",max,min,ave);
return 0;
}
float average(float array[],int n)//定义形参,有一个形参是数组
{
int i;
float aver,sum=array[0];
Max=Min=array[0];
for(i=1;i<n;i++)
{
if(array[i]>Max)
Max=array[i];
else if(array[i]<Min)
Min=array[i];
sum=sum+array[i];
}
aver=sum/n;
return aver;
}
在不必要时不要使用全局变量
①全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要是才开辟单元。
②它使用函数的通用性降低了,因为如果在函数中引用了全局变量,那么执行情况会受到有关的外部变量的影响,如果将一个函数移到另外一个文件中,还要考虑把有关的外部变量与其他文件的变量同名时,就会出现问题,这样就降低了程序的可靠性和通用性
③使用全局变量过多,会降低程序的清晰性,很难清楚判断出每个瞬时各个外部变量的值。
如果全局变量与局部变量同名,会有什么结果呢?
#include<stdio.h>
int a=3,b=5;//全局变量
int max(int a,int b);//函数的声明
int main()
{
int a=8;//局部变量a
printf("max=%d\n",max(a,b));//使用局部变量a和全局变量b
return 0;
}
int max(int a,int b)//a,b是形参
{
int c;
c=a>b?a:b;
return c;
}
2.动态存储和静态存储
静态存储:是指在程序运行期间由系统分配固定的存储空间的方式
动态存储:在程序运行期间根据需要进行动态的分配存储空间的方式
2.1存储空间
(1)程序区
(2)静态存储区:全局变量在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。在程序过程中它们占据固定的存储单元,而不是动态的进行分配和释放。
(3)动态存储区
在动态存储区中存放以下数据:
①函数形式参数,在调用函数时给形参分配存储空间
②函数中定义的没有关键字static声明的变量,即自动变量
③函数调用时的现场保护和返回地址等
这些数据在函数调用开始时分配动态存储空间,函数结束时释放这些空间,在程序执行过程中,这种分配和释放是动态的,如果在一个程序中两次调用同一函数,而在此函数中定义了局部变量,在两次调用时分配给这些局部变量的存储空间的地址可能是不相同的。
3.局部变量的存储类型
变量和函数都有两个属性,数据类型(整型,浮点型)和数据的存储类别(静态存储和动态存储)。
存储类别有4种
自动的auto
静态的statis
寄存器register
外部的extern
3.1自动变量(auto)
如果变量没有声明为statis存储类型,都是动态地分配存储空间,数据存储在动态存储区中。例如:局部变量,形参。
定义:在调用函数时,系统会给变量自动分配存储空间,在函数调用结束时就自动释放这些存储空间,这类局部变量称为是自动变量。
程序中大多数的变量属于自动变量,auto可以省略不写。
int f(int a)//定义一个f的函数,a为形参
{
auto int b,c;//定义b,c为自动变量
//等价于int b,c;
}
3.2静态局部变量(static局部变量)
定义:
在函数调用结束后局部变量的值不消失而继续保持原来的值,即占用的存储单元不释放,在下一次调用该函数时,该变量的值是上一次函数调用结束的值,用static关键字进行声明。
#include<stdio.h>
int f(int);//函数的声明
int main()
{
int a=2,i;//自动局部变量
for(i=0;i<3;i++)
printf("%d\n",f(a));//输出f(a)的值
return 0;
}
int f(int a)
{
auto int b=0;//自动局部变量
static c=3;//静态局部变量
b=b+1;
c=c+1;
return a+b+c;
}
分析:
第一次:a=2;b=0;c=3;b=b+1=1;c=c+1=4;a+b+c=7;
因为c是一个静态局部变量,并不会立即释放值。
所以在第二次调用该函数的时候,
第二次:b=0;c=4(上一次调用的值)
3.3静态变量和自动变量的区别
(1)静态局部变量属于静态存储类别,在静态存储区内存储单元,在整个程序:运行期间都不释放;自动变量属于动态存储类别,分配在动态存储空间,调用函数后就释放。
(2)如果对静态局部变量赋初值,以后每次都用该函数时不会在重新赋初值而是保留上次函数调用结束的值;自动变量赋初值,每次调用函数后都会重新赋初值。
(3)如果没有对静态局部变量赋初值,编译会自动赋上0或’\0’;自动变量不赋初值便是一个不确定的值,因为每次函数调用结束后存储单元已经释放,下一次调用又会重新分配存储单元,而存储单元中的内容是不可知的。
(4)静态局部变量在函数调用结束后任然可以存在,其他函数不能引用它。
(5)静态存储降低了程序的可读性
//输出1到5的阶乘
#include<stdio.h>
int fac(int);
int main()
{
int n;
for(n=1;n<=5;n++)
{
printf("d!=%d\n",n,fac(n));
}
return 0;
}
int fac(int n)
{
static int f = 1; //保留上次调用结束时的值
f = f*n;
return f;
}
3.4寄存器变量(register变量)
定义:将局部变量的值存放在CPU中的寄存器中,需要用时直接从寄存器中取出参加运算,而不必再到内存中去存取。对寄存器的存取速度远远高于对内存的存取速度,可以提高执行效率。
例如:
register int f;//f为寄存器变量
3.5注意
自动变量存储在动态存储区
静态局部变量存储在静态存储区
寄存器存储在CPU中的寄存器中
4.作用域
一般来说,外部变量是在函数的外部定义的全局变量,它的作用域是从变量的定义处开始到本程序文件的末尾,在此作用域内,全局变量可以为程序中各个函数所引用。
扩展外部变量的作用域有以下三种情况
4.1extern 作用一
外部变量不在文件的开头定义,有效作用范围只限于定义到文件结束。在定义之前的函数就不能引用该外部变量。如果需要使用该变量,需要在变量之前加关键字"extern".
表示把外部变量的作用域扩展到此位置
例如:调用函数,求3个整数中的大者。
用extern声明外部变量,扩展外部变量在程序文件中的作用域。
#include<stdio.h>
int max;
int main()
{
extern int A,B,C;//外部变量的作用域从此处开始
//等同于int A,B,C;因为她不是定义变量,也可以不指定类型只需要写出外部局部变量名即可。
printf("Please enter three integer numbers:");
scanf("%d%d%d",&A,&B,&C);
printf("max is %d\n",max());
}
int A,B,C;
//定义外部变量ABC,放在了main之后,本来在main函数中是不能引用外部变量ABC,
//但是main函数中对ABC三个变量使用了extern,把ABC的作用域进行了扩展
//否则编译的时候会出错,系统无法得知ABC是后来定义的外部变量
//由于ABC是外部变量,所以在调用max函数的时候不用参数传递,在函数中使用外部变量ABC的值
int max()
{
int m;
m = A>B?A:B;
if(C > m) m = C;
return m;
}
4.2extern作用二
如果一个程序由多个源文件组成,同时都需要用到一个外部变量x,不能分别在各自文件中定义一个外部变量x,否则在程序连接时会出现“重复定义”错误。
正确做法:一个文件定义局部变量x,另一个文件中用extern对x变量进行声明,编译的时候就可以把x的作用域扩展到本文件中。如果有多个文件都需要使用该变量,都需要加上extern
例:给定b的值,输入a和m,求a*b和a^m的值。
file1文件中包含主函数,file2中用extern声明外部变量,把变量的作用域扩展搭配file2文件。
//file1.c
#include<stdio.h>
int A;//定义外部变量
int power(int);
int main()
{
int b=3,c,d,m;
printf("enter the number a and its power m:\n");
scanf("%d,%d",&A,&m);
c=A*b;
printf("%d*%d=%d\n",A,B,C);
d = power(m);
printf("%d ** %d=%d\n",A,m,d);//**表示幂次
return 0;
}
//file2.c
extern A;
//声明在本文件中是一个在“其他文件中定义过的外部变量”
//A的作用域从file1.c扩展到file2.c
int power(int n)
{
int i,y=1;
for(i=1;i<=m;i++)
y*=A;
return y;
}
4.3static外部变量作用域限制在本文件中
如果已经确认其他文件不需要引用本文件的外部变量,就可以对本文件中的外部变量加上static,成为静态外部变量,以免被其他文件误用,相当于把本文件的外部变量对外界“屏蔽”起来。
static声明变量的作用:
(1)对局部变量用static声明,把它分配到静态存储区域,该变量在整个程序执行期间不释放,其所分配的空间始终存在。
(2)对全局变量用static声明,则该变量的作用域只限制于本文模块(即被声明的文件中)
例如:
//file1.c
static int A;
int main()
{
.....
}
//file2.c
extern A;
void fun(int n)
{
A = A*n;//出错
}
注意:
(1)声明局部变量的存储类型和声明全局变量的存储类别的含义是不同的。
(2)对于局部变量来说,声明存储类型的作用是指定变量存储的区域(静态存储区或动态存储区)以及产生的生存期的问题。
(3)对于全局变量来说,由于都是在编译时分配内存的,都存放在静态存储区,声明存储类型的作用**是变量作用域的扩展问题。**
5.存储类别的小结
数据的定义分为(1)数据类型(2)存储类别
static int a;//静态局部整型变量或静态外部整型变量
auto char c;//自动变量,在函数内定义
register int d;//寄存器变量,在函数内定义
extern b;//将已经定义的外部变量b的作用域扩展
(1)作用域角度,有全局变量和局部变量
作用域角度 (空间角度)
(1)全局变量:①静态外部变量(只限于本文本使用static)②外部变量extern(即非静态的外部变量,允许其他文件引用)
(2)局部变量 :①自动变量auto,即动态局部变量(离开函数,值就消失)②静态局部变量static(离开函数,值仍保留)③寄存器变量(离开函数,值就消失)④(形式参数可以自定义为自动变量或寄存器变量)
(2)从变量的生存周期来区分(时间角度)
变量的生存周期分:
(1)动态存储:①自动变量(本函数内有效)②寄存器变量(本函数内有效)③形式参数(本函数内有效)
(2)静态存储:①静态局部变量(函数内有效)②静态外部变量(本文件内有效)③外部变量(用extern声明后,其他文件可引用)
(3)变量值存放的位置
变量值存放的位置
(1)内存中静态存储区:①:静态局部变量②静态外部变量(函数外部静态变量)③外部变量(可为其他文件引用)
(2)内存中动态存储区:自动变量和形式参数
(3)CPU中寄存器:寄存器变量