C和指针-作用域、链接属性以及存储类型

        之前对作用域链接属性以及存储类型这三个概念总是弄混,今天在C和指针上看到了其对着三个定义的解释觉得很受启发,因此就在这里记录一下,方面日后自己进行复习。

1. 作用域

        当变量在程序中的某个部分被声明之后,它只在程序中的某个区域内可用(作用域其实就是指变量的可用域)。比如,在函数中定义的局部变量就只能在该函数中使用,一旦出了这个函数的就无法进行使用了。目前,主要有代码块作用域函数作用域文件作用域以及原型作用域四种。

#include <iostream>

using namespace std;

int a;                          // a是文件作用域
int func(int b);                // func文件作用域; b是原型作用域

int func(int temp){             // func是文件作用域; temp是代码块作用域
    int c;                      // c是代码块作用域
    void func2(int d);          // func2是代码块作用域; d是原型作用域
    {
        int e;                  // e是代码块作用域
    }
}

int main(){

    return 0;
}

1.1 代码块作用域

        在两个花括号之间定义的变量都具有代码块作用域,也就是说这些变量只在这个代码块之间可用,一旦出了代码块就不可用了。特殊一点的是函数中的形式参数,由于形式参数只在当前的函数代码块中可用,因此形式参数也是代码块作用域。

        如上述代码所示,变量temp变量c函数func2以及变量e的作用域类型都是代码块作用域。

1.2 文件作用域

        任何在所有代码块之外声明的标识符都具有文件作用域,这些标识符从它们声明之处到它们所在的源文件结尾都是可用的。另外,通过#include指令包含的文件中的变量声明一样可以在当前文件中可用,就好像它们直接在当前文件中声明。

        在上述代码中,变量a函数变量func都具有文件作用域,如果上述代码被其他文件所include,那么上述两个变量也同样在其他文件中的作用域是文件作用域。

1.3 原型作用域

        原型作用域只适用于在函数原型中声明的参数。比如在func以及func2两个函数原型中定义的b和d变量,它们都只具有原型作用域。

1.4 函数作用域

        当使用goto时,才会涉及到函数作用域。但是在编程中通常不会使用到goto语义。因此这个不必了解,知道有这么个作用域类型就行。

2. 链接属性

        当组成一个程序的各个源文件分别被编译了之后,那么所有的目标文件以及那些从一个或者多个函数库中引用的函数将会被链接在一起,从而构成一个可执行程序。然而,如果在几个不同的源文件中存在着相同名称的标识符,这些标识符是会像Pascal那样表示同一个实体,还是表示不同的实体?此时,标识符的链接属性就派上了用场,它会会决定这些相同名称的标识符到底是属于哪种实体。

        链接属性一共有三种:外部的(external)内部的(internal)以及无链接属性的(none)。没有链接属性(none)的标识符总是被当做是一个单独的个体,也就是说这些标识符的多个声明都将会被当做是独立的、不同的实体;内部链接属性(internal)的标识符表示在同一个源文件内的所有声明都指向同一个实体,但是位于不同源文件中的多个声明则属于不同的实体;外部链接属性(external)的标识符无论在哪个文件中声明了多少次都表示同一个实体。

#include <iostream>

using namespace std;

int a;                          // a是文件作用域
int func(int b);                // func文件作用域; b是原型作用域

int func(int temp){             // func是文件作用域; temp是代码块作用域
    int c;                      // c是代码块作用域
    void func2(int d);          // func2是代码块作用域; d是原型作用域
    {
        int e;                  // e是代码块作用域
    }
}

int main(){

    return 0;
}

        仍以上述代码为例来阐述变量的链接属性:变量b、函数变量func以及函数变量func2都标示的是外部链接属性(external),只不过它们都省略了extern关键字。

        然而,随着工程项目越做越大且每个程序员都会负责项目中的一小部分,难免会出现不同文件下变量名或者函数名重名的情况。因此,我们可以借助static关键字,将外部链接的变量变成内部链接,从而缩小变量的链接范围。比如,我们希望将外部链接属性的func函数变成内部的链接函数,则可以这样使用:

int a;                          // a是文件作用域
static int func(int b);                // func文件作用域; b是原型作用域

3. 存储类型

        变量的存储类型是指存储该变量值的内存类型,它决定了该变量何时创建、销毁以及它的值将会保持多久。有三个地方可以用于存储变量:内存区、堆栈区以及寄存器区。

#include <iostream>

using namespace std;

int a;                          // 静态存储区
int func(int b);                // func保存在静态存储区;b保存在堆栈区

int func(int temp){             // func保存在静态存储区, temp保存在堆栈区
    int c;                      // c保存在堆栈区
    void func2(int d);          // func2以及d保存在堆栈区
    {
        register e;                  // e保存在寄存器区
    }
}

int main(){

    return 0;
}

3.1 内存区

        在代码块之外声明的变量总是存储在静态内存中的,这类变量称之为静态变量(static)。静态变量在程序运行之间就创建了,在程序运行的整个期间始终存在。比如变量a以及func函数变量都保存在内存区,它们都是静态变量。

3.2 堆栈区

        在代码块内声明的变量的存储类型都是自动的(automatic),它们是自动变量(auto)。比如变量b以及变量c都是自动变量,它们都保存在堆栈区。如果给自动变量加上static关键字进行修饰的话,会将自动变量变成静态变量,改变其存储类型。

3.3 寄存器区

        使用register修饰的变量都是寄存器变量,它们将直接保存在读写速度都很快的寄存器中,一般而言只会将那些经常使用的变量才定义为寄存器变量,从而提高读写速度。

4. static关键字

        当应用于不同的上下文环境时,static可以带来不同的作用。

(1)当static用于函数的定义,或者用于对代码块之外的变量进行声明时,static可以起到修改标识符链接属性的作用,将其从外部链接属性变为内部链接属性,但是该标识符的作用域以及存储类型并不会受到影响。

(2)当static用于代码块内部的变量声明时,它可以修改变量的存储类型,将自动变量变成静态变量,但是变量的作用域以及链接属性并不会受到影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值