pointer on C_3 作用域 链接 存储类型

2.5作用域

标识符的作用域:程序中该标识符可以被使用的区域

编译器可以识别4种不同类型的作用域:

文件作用域:任何在所有代码块之外声明的标识符都具有文件作用域

代码块作用域:(代码块:位于一对花括号之间的所有语句)

    任何在代码块开始位置声明的标识符都具有代码块作用域。函数定义的形式参数也具有代码块作用域。

当代码块处于嵌套状态时,声明于内层代码块的标识符作用域到达该待毛孔的尾部便告终止。

当内层代码有一个标识符与外层代码的一个标识符同名,外层代码的那个标识符无法在内层代码块中通过名字访问。

原型作用域:从变量定义一直到原型声明的末尾

intceshi(int b);

intmain(void){

        return 0;

}

 

intceshi(int a)

{

         return (a+1);

}

函数作用域:适用于语句标签goto,最好不要用该方式,难维护!

2.6链接属性

那么问题来了,如果相同的标识符出现在几个不同的源文件中时,它们表示的是同一个实体,还是不同的实体?

    标识符的链接属性决定如何处理在不同文件中出现的标识符,标识符的作用域与它的链接属性有关,但这两个属性并不相同。

 

链接属性分为3种:external、internal、none

1.none的标识符总是被当作单独的个体,也就是说该标识符的多个声明被当作独立不同的实体;具有代码块作用域或者函数原型作用域的变量有空链接,意味着它们是由其定义所在的代码块或函数原型私有。

2.internal的标识符在同一个源文件内的所有声明中都指同一个实体,但位于不同源文件的多个声明则分属不同的实体,static声明

external的标识符不论声明多少次、位于几个源文件都表示同一个实体,extern声明

具有文件作用域的变量可能有内部或者外部链接,例如:全局变量、子函数

 

关键字externstatic用于在声明中修改标识符的链接属性

1.如果某个声明在正常情况下具有external属性,在它前面加上static关键字可以使它的链接属性变为internal。

例:

int b;//全局变量,extern链接

staticint b;//internal链接,变量为这个源文件所私有。

 

staticint c(int b)//防止被其他源文件调用

 

2.extern关键字的规则更为复杂,它为一个标识符指定external链接属性,这样便可以访问在其他任何位置定义的这个外部变量/全局变量。

当extern关键字用于源文件中第一个标识符的第1次声明时,它指定该标识符具有external链接属性

但是,如果它用于该标识符的第2次或以后的声明时,它并不会更改由第1次声明所指定的链接属性。

例:

static inti;

intfunc()

{

         extern int i;

}

2.7存储类型

变量的存储类型是指存储变量值的内存类型

三个地方用于存储变量:普通内存、运行时堆栈、硬件寄存器。

变量的缺省存储类型取决于它的声明位置。

1.静态变量:存储于静态内存中的变量(例如全局变量和static申明的局部变量)。在程序运行之前创建,在整个执行期间时钟存在,它始终保持原先的值,除非赋予它不同的值或者程序结束。

 

2.自动变量:在代码块部声明的变量,存储于堆栈中。在程序执行到声明自动变量的代码时,自动变量才被创建,当程序执行离开该代码块时,这些自动变量便自行销毁。

如果给自动变量加上static,使它的存储类型从自动变成静态,则变量在整个程序执行过程中一直存在,但是变量的作用域不会改变,仍然是在该代码块内部。

 

3.寄存器变量:register用于声明自动变量,这些变量应该存储于机器的硬件寄存器而不是内存之中。

编译器有自己的一套寄存器优化方案,可能忽略register。

在典型情况下,你希望把使用频率最高的那些变量声明为寄存器变量。在有些计算机中,如果把指针声明为寄存器变量,程序的效率将得到提高。

还可以把函数的形参声明为寄存器变量,编译器会在函数的起始位置生成指令,把这些值从堆栈复制到寄存器中,但是有可能反而更费时间。

 

初始化

 

补充:c里等号的意义是分两种情况,一种是在表达式里, 而另一种是在变量声明中。在变量声明中的等号不可以看作是赋值,它只是初始化,也就是说它的意义只是告诉编译器如何初始化这个内存空间。而表达式中的 = 就是赋值的意思了。

 

静态变量的初始化,可以把可执行程序文件想要初始化的值放在变量将会使用的位置,当可执行文件载入到内存时,已经保存了正确初始值的位置将赋值给那个变量。缺省值为0。

 

自动变量的初始化,当程序链接时还无法判断自动变量的存储位置。显式初始化,将在代码块的起始处插入一条隐式的赋值语句

 

/*****************************************************************************/

静态变量:其初始化值被放在程序执行时将使用的位置,所以不需额外时间,也不需额外指令。如果不显示初始化,静态变量将被初始化为0。

 

自动变量:程序链接时仍无法判断变量的存储位置。所以,自动变量没有缺省的初始值,而显示初始化将在代码的起始处插入一条隐式赋值语句。

 

这个技巧造成4个后果:

1.自动变量初始化较之赋值语句效率并无提高。除了声明为const的变量之外。

2.自动变量所在函数块每次执行时,都要对自动变量重新赋值。静态变量(全局变量和静态局部变量)只是在程序开始执行前初始化一次。

3.由于初始化在运行时执行,因此可以使用任何表达式作为初始化值。

4.除非对自动变量显式初始化,否则当自动变量创建时,它的值一定是垃圾。

那么问题来了,为什么静态变量的初始化不能使用表式?例如:static  int a = b + c

因为静态变量在程序执行之前创建!如果b是自动变量的话,b的值不确定,从而a的值也无法确定。即使b是静态变量也不行!

#include<stdio.h>

 

int a=0;

int b=1;

intc=a+b;

 

intmain(int argc, char *argv[]) {

        

         printf("%d %d %d",a,b,c);

         return 0;

}

报错:int c=a+b;[Error]initializer element is not constant

/*****************************************************************************/

 

2.8static关键字

第一种情况:函数定义、代码块之外的变量声明

static用于修饰标识符的链接属性,从external变成internal,但标识符的存储类型和作用域不受影响。用这种方式声明的函数或变量只能在声明它们的源文件中访问。

第二种情况:代码块内部的变量声明,static关键字用于修改变量的存储类型,从自动变量变成静态变量,但变量的链接属性和作用域不受影响。用这种方式声明的变量在程序执行之前创建,并在程序的整个执行期间一直存在,而不是在每次代码开始执行时创建,在程序执行完之后销毁!。

总结:

变量类型

声明的位置

是否存于堆栈

作用域

如果声明static

全局

所有代码块之外

从声明处到文件尾

不允许从其他源文件访问

局部

代码块起始处

整个代码块

程序执行之前,变量存于静态内存中,在程序执行期一直保存

形式参数

函数头部

整个函数

不允许

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值