C语言的变量作用域

来源:互联网 发布:软件著作权 开源代码 编辑:程序博客网 时间:2024/05/17 06:37

C语言的变量作用域及头文件

关于C语言的变量作用域和头文件的问题都是比较基础的问题,但是这些问题在实际使用过程中的概念不清和混乱会对一个多文件的项目的组织结构及文件结构造成很大的影响,使得项目本身的脉络也变的很模糊。


1、作用域

      关于C语言的变量作用域和头文件的问题都是比较基础的问题,但是这些问题在实际使用过程中的概念不清和混乱会对一个多文件的项目的组织结构及文件结构造成很大的影响,使得项目本身的脉络也变的很模糊。

    一个C变量的作用域:

     分类一: 代码块作用域、函数原型作用域,和文件作用域。

  

     函数作用域(Funtion Scope),标识在整个函数中都有效。只有语句标号属于函数作用域。

     文件作用域(File Scope):标识从声明的位置开始直到这个程序文件的末尾都有效。

     块作用域(Block Scope),标识位于{}括号中(函数体或语句块),从它声明的位置开始到右}括号之间有效。函数定义的形参也算块作用域,从声明的位置开始到函数末尾之间有效。

     

     函数原型作用域(Funtion Prototype Scope),标示符出现在函数原型中,这个函数原型只是一个声明而不是定义(没有函数体),那么标示符从声明的位置开始到这个原型末尾之间有效。例如,void add(int num);中的num。

     分类二:代码块作用域和文件作用域。 代码块作用域和文件作用域也有另一种分类方法,局部作用域和全局作用域。

     代码块作用域:代码块作用域:代码块是指一对花括号之间的代码,函数的形参虽然是啊在花括号之前定义也属于代码作用域。C99中把代码块的概念扩大到包括由for循环、while循环、do while循环、if语句所控制的代码。在代码块作用域中,从该变量被定义到代码块末尾该变量都可见。

     文件作用域:一个在所有函数之外定义的变量具有文件作用域。具有文件作用域的变量从它的定义到包含该定义的文件结尾都是可见的。

2.链接

      一个C语言变量具有下列链接之一:外部链接(external linkage),内部链接(internal linkage)或空链接(no linkage)。

      空链接:具有代码块作用域或者函数原型作用域的变量就具有空链接,这意味着他们是由其定义所在的代码块或函数原型所私有。 、

      内部链接:具有文件作用域的变量可能有内部或外部链接,一个具有文件作用域的变量前使用了static标识符标识时,即为具有内部链接的变量。一个具有内部链接的变量可以在一个文件的任何地方使用。

      外部链接:一个具有文件作用域的变量默认是具有外部链接的。但当起前面用static标识后即转变为内部链接。一个具有外部链接的链接的变量可以在一个多文件程序的任何地方使用。

eg: 

static int a;

(在所有函数外定义) int b;

(在所有函数外定义) 外部链接变量 main(){

     int b;    //空链接,仅为main函数私有

}


3、存储时期

         一个C语言变量有以下两种存储时期之一:(未包括动态分配malloc和free等)静态存储时期(static storage duration)和自动存储时期(automatic storage duration)和动态存储时期。

      静态存储时期:如果一个变量具有静态存储时期,它在程序执行捡起将一直存在。具有文件作用域的变量具有静态存储时期。   注意:对于具有文件作用域的变量,关键字static表明链接类型,而不是存储时期。一个使用了static声明了的文件作用域的变量具有内部链接,而不是文件作用域变量,无论他具有内部连接,还是具有外部链接,都是静态存储时期。

      动态存储时期:具有代码块作用域的变量一般情况下具有自动存储时期。在程序进入定义这些变量的代码块时,将为这些变量分配内存,当退出这个代码块时,分配的内存将被释放。

[cpp] view plain copy
 print?在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3.   
  4. #include <iostream>  
  5.   
  6. using namespace std;  
  7.   
  8. void add(int num);      //文件作用域,外部链接  
  9. void change_sum();      //文件作用域,外部链接  
  10.   
  11. int sum = 1;            //文件作用域,外部链接,静态存储时期  
  12.   
  13. int main(int argc,char *argv[])  
  14. {  
  15.     int num = 5;        //函数作用域,空连接  
  16.     add(num);             
  17.     printf("main num=%d",num);  /*输出5*/  
  18.   
  19.     //内层定义覆盖原则,当内层代码块定义了一个与外层代码块相同时名字的变量时,  
  20.     //运行到内层代码块是,使用内层定义的变量,离开内层代码块是,外层变量恢复,此时sum为for中定义的  
  21.     //sum,而不是全局的sum  
  22.   
  23.     for(int sum = 0,num = 0;num<5;num++)         //代码块作用域,空连接,自动存储时期  
  24.     {  
  25.         sum += num;  
  26.         printf("====================/n");    
  27.         printf("for num=%d/n",num);         //输出0-5    
  28.         printf("for sum=%d/n",sum);         //输出0-5的叠加和    
  29.     }  
  30.   
  31.     printf("======================/n");  
  32.     {  
  33.         int i;      //代码作用域。仅在该大括号内可见。空链接,自动存储时期  
  34.         for(i = 0;i<10;i++);  
  35.         printf("i=%d/n",i);  
  36.     }  
  37.   
  38.     //printf("i=%d/n",i);       //编译不能通过  
  39.     printf("main sum = %d/n",sum);  //输出0  
  40.     printf("main num = %d/n",num);  //输出5  
  41.     change_sum();  
  42.     printf("file sum=%d/n",sum);    //输出1。全局的sum。内层定义覆盖原则。    
  43.     system("PAUSE");    
  44.     return 0;  
  45. }  
  46.   
  47. void add(int num)                   //代码作用域  
  48. {  
  49.     num++;  
  50.     printf("add num= %d/n",num);    /*输出6*/  
  51. }  
  52.   
  53. void  change_sum()  
  54. {  
  55.     sum++;  
  56.     printf("change_sum = %d/n",sum);/*输出1*/  
  57. }  

    以上实例需要在C00标准下编译。(gcc支持c99的方法,编译时加入参数 -std = C99).

    从上例中可比较清楚地明白实例作用域和文件作用域的概念。另外注意文件作用域不仅限于变量也包括函数。在文件作用域中函数也是以其声明开始到文件结尾结束。而且当拥有文件作用域与拥有代码作用域变量同名时,不会发生冲突,而是以最小作用的变量可见。


 4、存储类修饰符

    static,用它修饰的变量是静态分配的,用它修饰的文件作用域的变量或函数具有internal linkage(内部链接)。

    atuto,用它修饰的变量在函数调用时自动在栈上分配存储空间,函数返回时自动释放,例如上例中的num其实就是用auto修饰的,只不过auto可以省略不写(此处与编译器有关,参照编译器不同而有所变动),auto不能修饰文件作用域的变量。

    register,编译器对于register修饰的变量会尽可能分配一个专门的寄存器来存储,但如果是在分配不开寄存器,编译器就会把它当做auto变量处理,register不能修改文件作用域的变量。  现在一般编译器的优化都做得很好了,它自己会想办法有效地利用CPU的寄存器,所以现在register关键字也用得比较少了。

    extern,上面已经将过,链接属性是根据一个标示符多次声明时是不是代表同一个变量或函数来分类的,extern关键字就用于多次声明一个标示符。


c语言使用作用域,链接和存储时期来定义了5种存储类:自动,寄存器,具有代码块的作用域的静态、具有外部链接的静态,以及具有内部链接的静态。

  • 五种存储类

存储类

时期

作用域

链接

声明方式

自动

自动

代码块

代码块内

寄存器

自动

代码块

代码块内,使用register

具有外部链接的静态

静态

文件之间

外部

所有函数之外

具有内部链接的静态

静态

文件之内

内部

所有函数之外使用关键字static

空链接的静态

静态

代码块

代码块内,使用关键字static


0 0