C语言标识符作用域、外部对象连接属性和变量的储存属性
标识符作用域
1. 标识符(identifier)用于代表程序中的对象,根据所代表的对象不同,可将标识符分为变量名、数组名、函数名、数据类型说明符、符号常量名(宏名)和语句标号。
2. 标识符的作用域:
- 文件作用域:指从标识符定义或声明位置起到源文件结尾的源文件范围。外部对象(全局变量名、全局数组名、函数名、在函数外自定义的数据类型名)都具有文件作用域,其作用域可以通过引用性声明扩大。全局变量的"定义"与全局变量的"声明"是不相同的,全局变量的定义只能有一次, 它的位置是在所有函数之外,而同一个文件中的全局变量声明可以是多次的,它可以在函数之内(哪个函数要用就在那个函数中声明)也可以在函数之外(在全局变量的定义点之前)。系统会根据全局变量的定义(而不是全局外部变量的声明)分配存储空间的。对于全局变量来讲,初始化只能是在"定义"中进行,而不是在" 声明"中。
#include<stdio.h> int x;//变量x的引用性声明,不需要建立存储空间 void main() { printf("%d",x); } int x=1;//外部变量x的定义,需要建立存储空间
- 函数作用域:指一个函数定义所覆盖的区域。
- 块作用域:指一个函数体内一个代码块(一条复合语句)的范围。块作用域总是嵌入在函数作用域内,一个块作用域还可以包含多个块作用域。
- 函数原型作用域:指引用函数的函数原型说明中使用的参数名的作用域。
3. 标识符作用域规则
①不允许同一作用域内定义或声明代表不同对象的同名标识符。
②允许不同作用域内定义或声明代表不同对象的同名标识符。
③内层作用域中访问的同名标识符是内层作用域中定义的标识符,此时外层作用域中定义的同名标识符被自动隐蔽不可访问。以下程序输出结果:2 2 2 2 5 0。
1 #include<stdio.h> 2 int x=0; 3 void f(); 4 5 int main() 6 { 7 int x; 8 for(x=1;x<5;x++){ 9 int x=2; 10 printf("%d",x); 11 } 12 printf("%d",x); 13 f(); 14 return 0; 15 } 16 17 void f() 18 { 19 printf("%d",x++); 20 }
外部对象连接属性
1. 同一个代码段中的函数名只允许在一个源文件中被定义一次,允许在多个源文件中被多次地引用性声明。
2. 它们具有两种连接属性之一:内部连接(internal linkage)和外部连接(external linkage)。分别对应储存类型说明符 static和extern。
extern 返回值类型说明符 函数名(形参类型表); extern 数据类型说明符 全局变量名;
变量的储存属性
1. 变量的生存周期属性
- 静态变量:生存周期与程序运行时间相同。
- 动态变量:生存周期与定义它的代码块被执行的时间相同。函数的形参都是动态变量。
- 局部变量有静态个动态之分。使用static声明的局部变量是静态的,使用auto或register声明的局部变量是动态的。
- 静态局部变量的生存周期与全局变量相同,但作用域与局部变量相同。
- 未指定初值时,静态局部变量和全局变量在编译时被初始化为0,动态局部变量的初值不确定。
//利用静态局部变量储存特性计算阶乘 long f(int n) { static long s; if(n<=1) s=1; else s*=n; return s; } int main(void) { int i; double k=0; for(i=1;i<=0;i++) k+=1.0/f(i); printf("%lf",k); return 0; }
2. 变量的储存器属性
- 静态变量在程序运行期间是始终存在的,全部是内存变量。
- 动态变量可以放在内存中也可以放在寄存器中。
- 寄存器没有地址,不能对register变量执行取地址操作。不能通过scanf函数对其赋值。
葡萄美酒夜光杯,欲饮琵琶马上催。