理解C语言的存储类

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

存储类时期作用域链接声明方式
自动自动代码块代码块内
寄存器自动代码块代码块内,使用关键字register
具有外部链接的静态静态文件外部所有函数之外
具有内部链接的静态静态文件内部所有函数之外,使用关键字static
空链接的静态静态代码块代码块内,使用关键字static

    我想大概可以不严谨的把相关概念与生活中的足球篮球运动做比较。先介绍一下背景吧,CPU、内存、硬盘分别对应比赛场、更衣室和酒店。平时数据就安安静静的躺在硬盘,需要计算时就来到内存做准备,整个计算过程在CPU中进行,计算结束后,数据首先回到内存,最后再返回硬盘。硬盘的数据是“静”的,CPU/内存的数据是“动”的,其中CPU分为计算器,控制器,寄存器和时钟,计算器的运行就相当于正在进行激烈的比赛,寄存器就是替补席,存放随时可能用到的数据。
    介绍完背景知识,可以进行基本概念的介绍了。变量和函数都可以分成不同的存储类,一个变量就相当于一名赛场上的运动员,函数就是战术,没错,类似“牛角”、“钻石”这样的战术。函数需要若干个变量来参与执行。“时期”和“作用域”分别是从时间和空间的角度进行定义的。时期分为自动和静态,自动意味着变量根据函数的需要灵活进行定义、使用和释放,就像运动员执行完相应战术,就可以下场休息了,战术需要的时候再上场;而静态表示变量被定义之后就一直持续到程序结束,就像运动员上场之后就一直待到比赛结束,所以说,一般情况下,自动使用较多,只有非常重要的变量才需要静态。
    作用域分为代码块作用域、函数原型作用域、文件作用域与函数作用域,有些类似足球场地,整个足球场就是文件作用域,作为全局变量的运动员拥有文件作用域,可以全场飞奔。将足球场地划分成后场,中场和前场几个区域,区域对应文件中的代码块,就像后卫一般在后场活动一样,代码块作用域的变量只能在代码块中生效。
    函数原型作用域(function prototype scope)翻译的让人很不容易理解,要说清楚函数原型作用域,需要先理解函数原型。函数原型(function prototype)实际上就是函数接口(function interface),声明了函数的返回类型、名称、参数类型和参数数量。将函数原型作为函数的声明,放在头文件中,预处理可以使程序拆分成编译单元,编译器将编译单元分别编译汇编成object文件,再由链接器组合成可执行文件或者库。关于函数原型作用域,我个人简单粗暴的理解是:函数原型中的参数具有函数原型作用域。以下面示例为例,函数原型中标识符“ lho”的范围始于逗号,结束于右括号。

#include <stdio.h>
 
/* 函数原型 */
int simple_add (int lho, int rho);
 
int lho;  /* 与函数原型中的 "lho" 不冲突 */
 
int main(void)
{
    printf("%d\n", simple_add(1,2));
 
    return 0;
}
 
int simple_add (int lho, int rho)
{
    return (lho+rho);
}

    链接是从空间的角度定义的,用于引用变量或函数。链接分为內链接、外链接和空链接。外链接和內链接比较好理解,它们的相同之处是都拥有文件作用域,定义变量或函数之后可以在本文件内任何地方进行引用;不同之处在于,外链接表示可以在其他文件中引用本文件的变量或函数,而內链接性质的变量或函数不能被其他文件引用。空链接表示不能被引用,代码块作用域的链接全是空链接,这其中“自动”和“寄存器”存储类比较好理解,因为调用完代码块,内存空间就释放了,数据不能保存下来也就谈不上引用了。具有代码块作用域的静态稍微有点复杂,用打车和开车形容比较合适。静态就是开自己的车,虽然平时车就停着不动(静态变量一旦创建,即使代码块调用结束也不会消失,会持续到程序结束),但别人不能开走(无法引用具有代码块作用域的静态变量,无法在其他文件中引用静态函数),需要的时候只有本人能启动(只有引用同一代码块才能使用静态变量,只有在本地文件中引用静态函数),而相对的,“自动”和“寄存器”就是打出租车了,因为本来就没有车,所以不可能把车借给别人。具有代码块作用域的静态变量示例如下:

#include<stdio.h>
void trystat(void);

int main(void)
{
    int count;

    for(count = 1;count <= 3;count++)
    {
        printf("Here comes iteration %d: \n", count);
        trystat();
    }
    
    return 0;
}

void trystat(void)
{
    int fade = 1;
    static int stay = 1;

    printf("fade = %d and stay = %d\n",fade++, stay++);
}

    这里的变量stay只有使用trystat函数才能调用,如果想在其他函数中使用,只有把它的作用域从代码块改为文件,即,把它改为全局变量:

#include<stdio.h>
void trystat(void);
void printstay(void);

static int stay = 1;
int main(void)
{
    int count;

    for(count = 1;count <= 3;count++)
    {
        printf("Here comes iteration %d: \n", count);
        trystat();
    }
    printstay();
    return 0;
}

void trystat(void)
{
    int fade = 1;

    printf("fade = %d and stay = %d\n",fade++, stay++);
}

void printstay(void)
{
    printf("This is function printstay, stay=%d\n",stay);
}

参考文档

[1]wikipedia.Function prototype[EB/OL].https://en.wikipedia.org/wiki/Function_prototype,2020-04-29.
[2]polytechnique.function_prototype_scope[EB/OL].http://www.enseignement.polytechnique.fr/informatique/INF478/docs/Cpp/en/c/language/function_prototype_scope.html,2020-01-01.
[3]Stephen Prata.C Primer Plus[M].人民邮电出版社:北京,2014:321-335.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值