存储类型

来源:互联网 发布:林弯弯淘宝网店 编辑:程序博客网 时间:2024/06/14 06:50

基础

        存储类型分为:自动变量,寄存器变量,具有外部连接的静态存储变量,具有内部链接的静态存储变量,空链接的静态存储变量。

        不同的存储类型提供了变量的作用域,链接以及存储时期的不同组合。存储时期就是变量在内存中的保留时间,作用域和链接一起表明变量程序的哪些部分可以通过变量名来使用该变量。

作用域

        它描述了程序中可以访问一个标识符的一个多个区域。主要分为:代码块作用域,函数原型作用域和文件作用域。

代码块作用域

        类似于Java中的局部变量。代码块是包含在开始花括号和结花括号之内的一段代码。例如整个函数,或者是一个复合语句。在某个代码块中声明的变量只对该代码块可见,具有代码块作用域——从该变量被定义的地方到该代码块结尾该变量均可见,超出该范围则不可见。

    while(1){        int a = 0;//只对该while循环代码块可见,超出该循环就无法使用    }    printf("%d\n",a);
        在c99中,将代码块的概念扩展到了if,for,while以及do while循环,即使这些代码没有用花括号括起来。如:
    for (int x  = 0; x<3; x++)        printf("%d",x);

        在该循环中,x被认为是for循环代码块的一部分,因此对整个循环来说x是可见的,出了该循环之后x就不可用。

函数原型作用域

        仅能在函数原型中使用的变量名。由于在声明函数原型时,一般不需要指定变量名,而且编译器也不关心变量名是什么。函数原型中名字起作用的一种情形是:函数中使用了变长数组。

文件作用域

        又称全局变量,在所有函数之外定义的变量。具有文件作用域的变量从它定义处到包含该定义的文件结尾处都是可见的。如果函数出现在定义语句之前,该函数将无法使用该变量。

链接

        链接分为空链接,外部连接和内部链接。

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

        内部链接:具有内部链接的变量可以在它定义的文件的任何地方使用。

        外部链接:具有外部链接的变量可以在一个或多个文件中使用。

        具有文件作用域的变量即可能具有内部链接也可能具有外部链接,关键看有没有被static修饰——被修饰过的变量具有内部链接

        总结:作用域决定该变量是局部变量还是全局变量,而链接决定别的文件是否能访问到该文件中的变量——类似于Java中private和public类型的全局变量

存储时期

        存储时期分为两种:静态存储和自动存储。

        静态存储:它在程序执行期间一直存在。所有的具有文件作用域的变量都是静态存储时期。

        自动存储:具有代码块作域的变量(被static修饰过除外)一般情况下是自动存储。在程序进入定义这些变量的代码块时,将为这些变量分配内存;退出这个代码块时,分配的内存将被释放。 

自动变量

        使用auto修饰的局部变量(该关键字可以省略),它具有自动存储,代码块作用域以及空链接。在默认情况下局部变量都是自动变量,它不会被自动初始化

        空链接与代码块作用域意味着只有在变量定义所在的代码块才可以通过名字访问该变量。

        如果内层代码块使用了和外层代码块相同的变量名,那么在内层代码块中使用就是内层代码块定义变量,直到离开内层代码块时外层定义的变量才恢复使用。

寄存器变量

        类似于自动变量,使用register进行声明,寄存器变量有可能被存储到寄存器中(寄存器的速度远大于内存,因此寄存器变量比自动变量更快地被访问和操作),并且寄存器变量无法取地址

        声明为一个寄存器变量仅仅是一个请求,有可能变量存储不到寄存器中。此时,该变量就是一个普通的自动变量,但仍旧无法取地址

具有代码块作用域的静态变量

        静态:表示变量的存储位置固定不动,并不是表示变量不可修改。

        使用static修饰的局部变量将是具有代码块作用域,空链接以及静态存储的变量。与自动变量不同的是,这种变量在代码块执行完毕之后并不会被回收,并且默认初始化为0,从一次函数调用到下一次函数调用,系统都记录着它的值。如:

char* string_in(char* p1, char* src){    static int a = 10;    printf("%d\n",a++);//第一次调用该函数时,输出10;再一次调用时输出11    return NULL;}
        由于a使用static修饰,所以string_in函数结束后,a变量的值依旧保存着。下一次再访问string_in时,a的值就是11。

        上面代码块也说明:静态变量并不属于代码块,但其作用域依旧在该代码块中,它在程序调入内存的时候就已经就位,把该变量放在函数中,只说明只有该函数才能看到该变量

具有外部链接的静态变量

        该类型具有文件作用域,静态存储以及外部链接。具有该类型的变量称为外部变量,将变量的声明放在所有函数之外即创建了一个外部变量,会自动初始化为0。外部变量与程序运行时间一样,并且它们不局限于一个函数,在一个特定函数返回时并不消失。

        要使用定义在别的文件中的具有外部链接的全局变量,必须在使用之前使用extern进行声明。如果变量在本文件中定义的,在使用该变量的函数中,可以使用extern进行再次声明,表明使用的是外部定义的变量,但不是必须要声明的。如下

extern int a;//引用了定义在别的文件中的变量achar* string_in( char*, char*);int main(int argc, const char * argv[]) {string_in(NULL,NULL);}char* string_in(char* p1, char* src){    printf("%d\n",a);    return NULL;}

        上述代码中,使用extern声明了全局变量a。这是因为a在别的文件中声明的,本文件如果想使用它必须使用extern进行再次声明,也可以自己定义变量a,但必须声明为内部链接的全局变量或者是局部变量。当然也可将声明语句(externint a;)放在string_in方法中。

        使用extern修饰变量时,不会引起内存的分配,即extern表明只是引用一个定义在别的地方的外部变量,此时不能进行初始化。

extern int a = 10;//有错,因为extern表明a只是引用一个外部变量,不会引起内存分配。
        并不是说不能对a进行赋值,在别的地方一样可以使用a=11这种赋值语句,但不能在声明的时候赋值。因为extern只是表示:引用一个已经在别的地方声明过的变量

变量共享

        通过在一个文件中定义变量,在其他文件中引用声明(使用extern)这个变量来实现共享。也就是说,除了一个定义声明外,其他所有声明都必须使用extern关键字,并且只有在定义声明中才可以对该变量进行初始化。

        注意:除非在第二个文件中使用extern声明了该变量,否则一个文件中定义的外部变量不可用于第二个文件。也就是说:想使用在别的文件中定义的外部变量,本文件必须重新使用extern进行声明——并且声明的时候不可进行再次初始化——否则不可用。

具有内部链接的静态变量

        该类型具有静态存储,文件作用域和内部链接。通过使用static在所有函数外部进行定义。该种类型的变量只可以被与它在同一个文件中的函数使用。类似Java中的private类型的全局变量。

总结

局部变量

        1,使用auto声明或不使用关键字进行声明:普通的局部变量。

        2,使用register声明:可能被存储在寄存器中,不能取地址。

        3,使用static声明:静态存储:在程序运行期间(即使在包含该变量的代码块并没有运行),该变量得以存在并保留其值。在函数执行完毕后,不会被回收,下次执行该函数时,该变量的值仍是上次的值。

        4,使用extern声明:使用本文件中的全局变量,若无则使用别的文件中的具有外部链接的全局变量。

全局变量

        1,使用extern声明:引用别的文件中定义的外部变量。

        2,不使用关键字修饰:定义一个外部变量,可以被程序所包含的任意一个文件中所包含的函数使用。

        3,使用static声明:定义一个具有内部链接的全局变量:只可以被与它在同一个文件中的函数使用。

0 0
原创粉丝点击