这一章(12章)的概念比较多.
内容在书12.1章.
1.作用域
对于变量来说,它起作用的范围是有规律的.如果在一个大括号里面被创建,那它的作用域就是这一对大括号内.
想一想下面的代码运行结果是什么.
# include <stdio.h>
int print(void);
int number = 10; //====================================1 -> 6
int main(void) {
int number = 100; //==================================2 -> 5
int i = 0;
for(; i < 1; i++) {
int number = 1000; //============================3 -> 6
printf("for循环中的number: %d\n", number); //=====4
}
printf("main函数中的number: %d\n", number); //========5
print();
return 0;
}
int print(void) {
printf("print函数: %d\n", number);//=================6
return 0;
}
运行结果
for循环中的number: 1000
main函数中的number: 100
print函数: 10
分别解释一下
1 -> 4 这个number在所有函数的前面,所以所有的函数都可以访问到.
main()中有新定义的number,所以这个number被"覆盖了".
而print()中没有定义新的number,所以输出的是这个number.
2 -> 5 main()函数中有一个新定义的number,而for循环中的number的作用域仅限for循环范围内.
3 -> 6 这个number的作用域仅限于for循环内.
2.链接
2.1 外部链接
非static,非局部变量,所有文件都可见.
int number = 10; // 外部链接
int main(void) {...}
2.2 内部链接
static,非局部变量,只在本文件可见.
static int number = 10; // 内部链接
int main(void) {...}
2.3 无链接
局部变量,只在作用域可见.
int main(void) {
int number = 100; //无链接
...
}
3.存储期
存储期描述了通过这些标识符访问的对象的生存周期.
3.1 静态存储期
如果对象具有静态存储期,那它在程序的执行期间一直存在.文件作用域变量具有静态存储期.
对于文件作用域变量,static表示其链接属性而不是存储期.
不论内部链接还是外部链接,所有的文件作用域变量都具有静态存储期.
//均具有静态存储期
int i = 100;
static float f = 2.7;
int main(void) {...}
3.2 线程存储期
用于并发程序设计,程序执行可以被分为多个线程.
从被声明到线程结束一直存在.
3.3 自动存储期
块作用域变量具有自动存储期.
程序进入这个块时,为这个变量分配内存,这个块运行结束,内存被释放.
而变长数组有些不同.它是从声明到块运行结束.
int main(void) {
int i = 100; //自动存储期
return 0;
}
4. 自动变量
属于自动存储类别的变量自动存储期,块作用域,无链接.默认情况下,声明在块或函数头中的任何变量都属于自动存储类别.
5. 寄存器变量
存储在CPU寄存器中,速度最快.
与普通变量不同的地方在于,由于是存储在寄存器中,所以寄存器变量无法获取地址.
可以用register修饰,需注意,这只是请求放入寄存器,并不是一定会被放入寄存器.如果未被放入寄存器,就会变成普通的自动变量.但是即使变为普通变量,仍无法对它使用地址运算符.
CPU寄存器空间可能不能容纳过大的数据.
6. 静态变量
"静态"在这里的意思是"变量在内存中原地不动,并不是值不变"(382页).具有文件作用域的变量自动具有静态存储期.
6.1 块作用域静态变量
可以创建具有静态存储期,块作用域的局部变量.和自动变量具有相同的作用域,但是程序离开它所在的函数之后,这些变量不会消失.意思就是,这些变量具有块作用域,无链接,但是具有静态存储期.
块中以存储类别说明符static(提供静态存储期)声明这种变量.
下面的number就是这样的变量.
# include <stdio.h>
int print(void);
int main(void) {
print();
print();
print();
return 0;
}
int print(void) {
int normal = 5;
static int number = 10;
printf("块作用域的静态变量number: %d\n", number++);
printf("普通局部变量normal: %d\n", normal++);
return 0;
}
运行结果
块作用域的静态变量number: 10
普通局部变量normal: 5
块作用域的静态变量number: 11
普通局部变量normal: 5
块作用域的静态变量number: 12
普通局部变量normal: 5
可以看到,以static修饰的变量number每次调用都会自增1,而普通的变量normal每次都是5,并没有自增.
说明以static修饰的变量整个程序运行期间只会被初始化一次,而普通的变量每次都会被初始化.
6.2 外部链接的静态变量
这种静态变量具有文件作用域,外部链接和静态存储期.
把变量的定义性声明放在所有函数外面就创建了一个外部变量.
为了指出函数中使用了外部变量,可以使用extern再次声明.
如果一个源代码文件使用的外部变量定义在另一个源代码文件中,则必须使用extern在该文件中再次声明.
int out; //外部变量,对所有函数可见
int arr[32]; //外部变量,对所有函数可见
extern int o; //如果o被定义在另一个文件中,则extern是必需的.
int main(void) {
int out; //局部变量,只在main()可见
extern int arr[];//extern可选,使用的是外部变量,不必再写数组大小
return 0;
}
int print(void){...}
6.3 内部链接的静态变量
这种变量具有静态存储期,文件作用域和内部链接.声明在所有函数的外部.下面代码中的number就是这种变量.
static int number = 10;
int main(void) {...}