本文转载自微信公众号「编程珠玑」,作者守望先生。转载本文请联系编程珠玑公众号。
我们提供的服务有:做网站、网站制作、微信公众号开发、网站优化、网站认证、罗甸ssl等。为近千家企事业单位解决了网站和推广的问题。提供周到的售前咨询和贴心的售后服务,是有科学管理、有技术的罗甸网站制作公司
前言
这些是编程语言中的基本概念,如果你还不是非常明确地清楚标题的问题,并且不知道作用域,链接属性,存储期等概念的具体含义,那么本文你不该错过。为了更加清晰的理解我们的问题,需要先了解三个概念:作用域,链接属性,存储期。
作用域
C语言中,作用域用来描述标识符能够被哪些区域访问。
而常见作用域有以下几种:
为了便于说明,我们来看一个例子,就很容易理解了:
- /****************************
- 作者:守望先生
- 来源:公众号编程珠玑
- 个人博客:https://www.yanbinghu.com
- ***************************************/
- #include
- 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变量有三种链接属性:
再稍作解释,没有static修饰,且具有文件作用域的变量,他们在链接时,多个同名标识符的变量最终都绑定到同一个实体。而static修饰的具有文件作用域的变量就不一样了,不同文件内,即便标识符名字相同,它们也绑定到了不同的实体。
因此,如果我们希望某个变量或函数只在某一个文件使用,那么使用static修饰是一个很好的做法。
同样的,来看一个例子。
- /****************************
- 作者:守望先生
- 来源:公众号编程珠玑
- 个人博客:https://www.yanbinghu.com
- ***************************************/
- #include
- 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具有块作用域,因此无链接属性。
存储期
实际上作用域和链接属性都描述了标识符的可见性,而存储期则描述了这些标识符对应的对象的生存期。存储期,也分下面几种:
同样地,我们通过下面的代码来更好地理解存储期
- /****************************
- 作者:守望先生
- 来源:公众号编程珠玑
- 个人博客:https://www.yanbinghu.com
- ***************************************/
- #include
- 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
- 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;
- }
总结
本文总结如下:
参考
https://en.wikipedia.org/wiki/Global_variables
https://en.wikipedia.org/wiki/Local_variable
《C11标准文档》
作者:守望,linux应用开发者,目前在公众号【编程珠玑】分享Linux/C/C++/数据结构与算法/工具等原创技术文章和学习资源。
新闻标题:学了这么久的C,作用域,存储器,链接属性该弄清楚了
URL分享:http://www.shufengxianlan.com/qtweb/news42/482192.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联