C/C++知识点之作用域,存储器,链接属性
小职 2020-11-18 来源 : 阅读 709 评论 0

摘要:本篇主要介绍了C/C++知识点之作用域、存储器、链接属性,希望对C/C++的学习有所帮助。

本篇主要介绍了C/C++知识点之作用域、存储器、链接属性,希望对C/C++的学习有所帮助。

C/C++知识点之作用域,存储器,链接属性


这些是编程语言中的基本概念,如果你还不是非常明确地清楚标题的问题,并且不知道作用域,链接属性,存储期等概念的具体含义,那么本文你不该错过。为了更加清晰的理解我们的问题,需要先了解三个概念:作用域,链接属性,存储期。

 

作用域

 

C语言中,作用域用来描述标识符能够被哪些区域访问。

 

而常见作用域有以下几种:

 

块作用域,可见范围是从定义处到包含该定义的块结尾

函数作用域,goto语句的标签就具有函数作用域

文件作用域,从定义处到定义该文件的末尾都可见。定义在函数之外的变量,就具有文件作用域了。

函数原型作用域,从形参定义处到原型声明结束

为了便于说明,我们来看一个例子,就很容易理解了:

 

#include <stdio.h>

int num1 = 222;         //定位在函数外,具有文件作用域

static int num2 = 111;  //定义在函数外,具有文件作用域

int swap(int *a,int *b); //这里的a,b是函数原型作用域

int swap(int *a,int *b)

{

    if(NULL== a || NULL == b)

        goto error;     

    else

    {

        int temp = *a;  //定义在函数内,块作用域

        *a = *b;

        *b = temp;

        return 0;

    }

    //printf("temp is %d\n",temp);   //因为temp具有块作用域,因此在这里不能直接使用

    error://goto语句的标签,函数作用域,因此在前面就可以引用

        {

            printf("input para is NULL\n");

            return -1;

        }

}

int main(void)

{

    printf("num1=%d,num2=%d\n",num1,num2);

    swap(&num1,&num2);  //num1 num2具有文件作用域,可以在main函数中直接使用

    printf("num1=%d,num2=%d",num1,num2);

    return 0;

}

可以看到,error标签具有函数作用域,整个函数内都可见,而temp具有块作用域,因此在大括号外部,不能直接使用它。而num1和num2具有文件作用域,因此main函数可以直接使用它。

 

链接属性

 

在《hello程序是如何变成可执行文件的》我们说到了编译的过程,最后一个步骤就是链接。链接属性决定了在不同作用域的同名标识符能否绑定到同一个对象或者函数。或者说,不同作用域的标识符在编译后是否是同一个实体。

 

c变量有三种链接属性:

 

外部链接,extern修饰的,或者没有static修饰的具有文件作用域的变量具有外部链接属性

内部链接,static修饰的具有文件作用域的变量具有内部链接属性

无链接,块作用域,函数作用域和函数原型作用域的变量无链接属性

再稍作解释,没有static修饰,且具有文件作用域的变量,他们在链接时,多个同名标识符的变量最终都绑定到同一个实体。而static修饰的具有文件作用域的变量就不一样了,不同文件内,即便标识符名字相同,它们也绑定到了不同的实体。

 

因此,如果我们希望某个变量或函数只在某一个文件使用,那么使用static修饰是一个很好的做法。

 

同样的,来看一个例子。

 

#include <stdio.h>

int a = 5;   //文件作用域,外部链接属性,其他文件可通过extern int a的方式使用该文件的a

static b = 6;  //文件作用域,内部链接属性,即便其他文件也有同名标识符,它们也是不同的

int main(void)

{

    int sum = 0 ; //无链接属性

    sum = a + b;

    printf("sum is %d\n",sum);

    return 0;

}

从代码中可以看到,a和b都具有文件作用域,a具有外部链接属性,而b具有内部链接属性,sum具有块作用域,因此无链接属性。

 

存储期

 

实际上作用域和链接属性都描述了标识符的可见性,而存储期则描述了这些标识符对应的对象的生存期。存储期,也分下面几种:

 

静态存储期,程序执行期间一直都在,文件作用域的变量具有静态存储期

自动存储期,它(变长数组除外)从块开始,到块末尾,因此,块作用域的变量具有自动存储期,它在栈中存储,需要显式初始化。

动态分配存储期,即通过malloc分配内存的变量。它在堆中存储,需要显式初始。

线程存储期,从名字可以知道, 它与线程相关,使用关键字_Thread_local声明的变量具有线程存储期,它从声明到线程结束一直存在。

关于初始化,可参考《C语言入坑指南-被遗忘的初始化》。

同样地,我们通过下面的代码来更好地理解存储期

 

#include <stdio.h>

int num1 = 222;         //静态存储期

static int num2 = 111;  //静态存储期

int add(int a,int b)

{

    static int tempSum = 0;  //静态存储期

    tempSum = tempSum + a + b;

    return tempSum;

}

int main(void)

{

    printf("num1=%d,num2=%d\n",num1,num2);

    int sum = 0;  //自动存储期

    sum = add(num1,num2);

    printf("first time sum=%d\n",sum);//sum = 333

    sum = add(num1,num2);

    printf("second time sum=%d\n",sum); //sum = 666

    return 0;

}

另外,如果我们通过nm命令查看编译出来的程序文件的符号表,我们可以找到num1,num2,tempSum,而没有sum,前者所用的内存数量在编译时就确定了。

 

$ gcc -g -o lifetime lifetime.c  

$ nm lifetime|grep num1

0000000000601038 D num1

$ nm lifetime|grep num2

000000000060103c d num2

$ nm lifetime|grep tempSum

0000000000601044 b tempSum.2289

$ nm lifetime|grep sum

$

什么全局变量,局部变量,静态局部变量,静态全局变量

 

到这里,我们就可以很容易区分上面的变量类型了。实际上这里只是换了一种说法:

 

全局:具有文件作用域的变量

 

静态:具有静态存储期或内部链接属性

 

局部:具有函数或块作用域的变量

 

因而结合起来,也就很好理解了。

 

局部变量:函数或块作用域的变量

静态局部变量:函数或块作用域,静态存储期

全局变量:具有文件作用域的变量

静态全局变量:内部链接属性的,具有文件作用域的变量

当然,这仅仅是为了区分它们,这并不是它们的严格定义。更好的方法,是通过代码来理解:

 

#include <stdio.h>

int num1 = 222;         //全局变量

static int num2 = 111;  //静态全局变量

int add(int a,int b)

{

    static int tempSum = 0;  //静态局部变量

    tempSum = tempSum + a + b;

    return tempSum;

}

int main(void)

{

    printf("num1=%d,num2=%d\n",num1,num2);

    int sum = 0;  //局部变量

    sum = add(num1,num2);

    printf("first time sum=%d\n",sum);//sum = 333

    return 0;

}

总结

 

本文总结如下:

 

具有文件作用域的变量具有静态存储期,并且具有链接属性

不希望其他文件访问的文件作用域变量最好使用static修饰

static关键字的含义需要结合上下文来理解

如果可以,全局变量应该尽量避免使用,因为它可能带来变量被意外修改

使用动态内存通常比栈内存慢,但是栈内存很有限



关注“职坐标在线”(Zhizuobiao_Online)公众号,免费获取最新技术干货教程资源哦

本文由 @小职 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程