深度解析C语言中的变量作用域、链接和存储期的含义

 更新时间:2021年5月31日 15:00  点击:2133

在c中变量有三种性质:
1、存储期限:变量的存储期限决定了变量占用的内存空间什么时候会被释放,具有动态存储期限的变量会在所属的程序块被执行时获得内存空间,在结束时释放内存空间。具有静态存储期限的变量在程序运行的整个期间都会占用内存空间。
2、作用域:变量有块作用域也有文件作用域,结合序章第一张图可以明白块作用域是在某些程序块内起作用,文件作用域是在整个c文件之内起作用。
3、链接:链接是各个文件之间的关系,具有内部链接的变量只在本文件内起作用,具有外部链接的变量可以在不同文件内起作用。具有无链接的变量只在某一个文件的某个函数内起作用。

在这里插入图片描述

C变量作用域、链接和存储期的含义

错误的定义C语言变量的作用域、链接和存储区在某种程度上会直接影响程序的设计,我们通过这篇博文介绍如何正确合理的定义一个C变量。

从定义一个C变量开始成为一个C高手

一、基本术语   

1.1 什么是对象(object)

       C语言中的对象含义与C++的完全不同,C语言中的对象指的是存储数据的一块内存。对象可以存储一个或多个值,一个对象可能并未存储实际的值,但是在存储适当的值时一定具有相应的大小。对象可以存在于程序的执行期,也可以仅存在于它所在函数的执行期。

  1.2 什么是标识符(identifier)

       标识符就是一个名称,通过这个标识符可以修改对象的内容。标识符可以在源代码的多文件中共享、可用于特定文件的任意函数中、可仅限于特定函数中使用,甚至只在函数中的某部分使用。

举个例子,我们定义一个int型变量point:

int point;

对象与标识符的关系如下图

在这里插入图片描述

二、作用域、链接和存储期三者关系

       存储期用来描述对象,所谓的存储期就是指对象在内存中可以保留多长时间。

       标识符用于访问对象,使用作用域(scope)和链接(linkage)描述标识符,标识符的作用域和链接表明了程序的哪些部分可以使用它。

三、作用域详解

作用域描述程序中可访问标识符的区域
一个C变量的作用域可以是块作用域、函数作用域、函数原型作用域和文件作用域,下面我们详细讲解每个作用域的含义。

  3.1 块作用域

       块是用一对花括号括起来的代码区域,定义在块中的变量具有块作用域块作用域变量的可见范围是从定义处到包含该定义的块的末尾

       另外,虽然函数的形式参数声明在函数的左花括号之前,但它们也具有块作用域,属于函数体这个块。

int Star_CongShanRuoShui(int user_id)
{
	int res = 0;
	......
	return 
}

👆上面code中“user_id”和“res”都具有块作用域

int Star_CongShanRuoShui(int user_id[] , int n)
{
	int res = 0;
	for(int i=0;i<n;++i)
	{
		......
		int q=0;   //q的作用域开始
		
		......
	}              //q的作用域结束
	......
	return 
}

👆上面code中变量“q”的作用域仅限于for循环的循环体中

    3.1.1 块概念的扩展

       C99将块概念扩展到包括for循环、while循环、do while循环和if语句所控制的代码,即使这些代码没有使用花括号括起来,也算是块的一部分,下面的code👇

#include<stdio.h>

int main()
{
	int Star_CSRS = 8;
	printf("[main] value of Star_CSRS is %d | address of Star_CSRS:%p\n",
			Star_CSRS ,&Star_CSRS);
	
	for(int Star_CSRS=0;Star_CSRS<4;++Star_CSRS)
	{
		printf("[for index] value of Star_CSRS is %d | address of Star_CSRS:%p\n",
			Star_CSRS ,&Star_CSRS);
			
		int Star_CSRS = 6;
		printf("[for] value of Star_CSRS is %d | address of Star_CSRS:%p\n",
			Star_CSRS ,&Star_CSRS);
		
		++Star_CSRS;
	}
	
	printf("[main] value of Star_CSRS is %d | address of Star_CSRS:%p\n",
			Star_CSRS ,&Star_CSRS);

	return 0;
} 

输出如下:

在这里插入图片描述

  • 在main中定义了变量Star_CSRS,在for循环头中定义的变量Star_CSRS 隐藏了main中的Star_CSRS
  • for的循环体中的Star_CSRS又隐藏了for循环头中的Star_CSRS

在这里插入图片描述  

 3.2 函数作用域

       函数作用域的概念仅限于goto语句的标签。这意味着即使一个标签首次出现在函数的内层块中,它的作用域也延伸至整个函数中(详细可以参考我的这篇博文)。

3.3 函数原型作用域

       用于函数原型的形参变量名,如下所示:

int Star_CongShanRuoShui(int user_id);

       函数原型作用域的范围是从形参定义处到原型声明结束。对于函数原型中的形参编译器只关心形参类型,不关系具体的形参名即使有形参名也不必与函数定义中的形参名相匹配

       只有在变长数组中,形参名才有意义,如下例(变长数组详细参考我的这篇博文):

int Star_CongShanRuoShui(int n ,int user_id[n]);

  3.4 文件作用域

       定义在所有函数外的变量具有文件作用域。具有文件作用域的变量,从它的定义处到该定义所在文件的末尾均可见(文件作用域变量也称为全局变量)。

翻译单元与文件

编译器将一个源代码文件和所有的头文件都看成一个包含信息的单独文件,这个文件被称为翻译单元一个翻译单元包括一个源代码文件和它所include的文件如果一个程序有多个源代码文件,那么这个程序也将有多个翻译单元一个文件作用域变量的可见范围其实是整个翻译单元(一个源代码文件+头文件)

四、链接详解

C变量有3中链接属性:无链接、内部链接、外部链接

  4.1 无链接

       具有块作用域、函数作用域和函数原型作用域的变量都是无链接变量。这意味着这些变量属于定义它们的块、函数或原型私有。

  4.2 内部链接

       内部链接变量只能在一个翻译单元中使用,该变量使用存储类别说明符static修饰,如下:

int Star_CSDN=1;                     //文件作用域,外部链接
static int Star_CongShanRuoShui=2;   //文件作用域,内部链接

int main()
{
	......
	return 0
}

  4.3 外部链接

       外部链接变量可以在多个文件中使用。外部链接变量的声明分为“定义性声明”和“引用性声明”。C编译器要求一个变量只能定义一次,重复定义编译器会报错。如果需要在其它文件中使用外部链接变量需要使用extern引用性声明这个变量,如下面cdoe:

//file a.c

//在文件a.c中定义一个外部链接变量Star_CongShanRuoShui
int Star_CongShanRuoShui = 2;

......

//file b.c

//文件b.c中使用extern引用性声明变量Star_CongShanRuoShui
extern int Star_CongShanRuoShui;

......

五、存储期详解

C对象有4种存储期:静态存储期、线程存储期、自动存储期、动态分配存储期。

  5.1 静态存储期

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

注意,对于文件作用域变量,关键字static表明了其链接属性,而非存储期。以static声明的文件作用域变量具有内部链接属性,但是无论是内部链接还是外部链接,所有文件作用域变量都具有静态存储期。

  5.2 线程存储期

       线程存储期用于并发程序设计,程序执行可被分为多个线程。具有线程存储期的对象,从被声明时到线程结束一直存在。以关键字__Thread_local声明一个对象时,每个线程都获得这个变量的私有备份

  5.3 自动存储期

       块作用域的变量通常都具有自动存储期。当程序进入定义这些变量的块时,为这些变量分配内存;当退出这个块时,释放刚才为这些变量分配的内存。通过这种做法可以实现内存的重复利用。

变长数组稍有例外,它的存储期从声明处到块的末尾,而不是从块的开始处到块的末尾

       我们上面说块作用域的变量通常都具有自动存储期,但是也能具有静态存储期。为了创建这样的变量,要把变量声明在块中,且在声明前加上关键字static,如下例:

int Star_CongShanRuoShui(int user_id)
{
	static int isStar = 0;
	......
	return 
}

       变量isStar存储在静态内存中,它从程序被载入到程序结束期间都存在。但是,它的作用域定义在Star_CongShanRuoShui()函数块中,只有在执行该函数时,程序才能使用isStar访问它所指定的对象(当然,也可以存储该变量的地址实现间接访问该对象)

 5.4 动态分配存储期

       程序运行时通过malloc()等内存分配函数分配的对象具有动态分配存储期,这样的对象需要使用free()函数进行销毁。

动态内存分配和变长数组在功能上有些重合,但是还是有所不同:

变长数组是自动存储类型用malloc函数创建的数组不必局限在一个函数中使用

在这里插入图片描述

以上就是深度解析C语言中的变量作用域、链接和存储期的含义的详细内容,更多关于C语言变量作用域、链接和存储期的资料请关注猪先飞其它相关文章!

[!--infotagslink--]

相关文章

  • C语言实现放烟花的程序

    这篇文章主要为大家详细介绍了C语言实现放烟花的程序,有音乐播放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-23
  • C语言中的字符(char)详细讲解

    本篇文章主要介绍C语言中char的知识,并附有代码实例,以便大家在学习的时候更好的理解,有需要的可以看一下...2020-04-25
  • PHP成员变量获取对比(类成员变量)

    下面本文章来给大家介绍在php中成员变量的一些对比了,文章举了四个例子在这例子中分别对不同成员变量进行测试与获取操作,下面一起来看看。 有如下4个代码示例,你认...2016-11-25
  • C#变量命名规则小结

    本文主要介绍了C#变量命名规则小结,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-09-09
  • 详解如何将c语言文件打包成exe可执行程序

    这篇文章主要介绍了详解如何将c语言文件打包成exe可执行程序,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-25
  • R语言 如何删除指定变量或对象

    这篇文章主要介绍了R语言删除指定变量或对象的操作方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-05-06
  • 解决vue的router组件component在import时不能使用变量问题

    这篇文章主要介绍了解决vue的router组件component在import时不能使用变量问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-27
  • jQuery实现鼠标滑过链接控制图片的滑动展开与隐藏效果

    本文实例讲述了jQuery实现鼠标滑过链接控制图片的滑动展开与隐藏效果。分享给大家供大家参考,具体如下:这里演示jQuery实现鼠标移动到链接上,滑动展开/隐藏图片效果,鼠标放在“上一页”“下一页”上,立即浮现出所对应的图...2015-10-30
  • Vue select 绑定动态变量的实例讲解

    这篇文章主要介绍了Vue select 绑定动态变量的实例讲解,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-10-23
  • 深入理解PHP变量的值类型和引用类型

    在PHP中,大部分变量类型,如字符串,整型,浮点,数组等都是值类型的,而类和对象是引用类型,在使用的时候,需要注意这一点。看到网友在讨论PHP的&符号,要彻底理解它的用法,就有必要讨论一下变量的两种形式。PHP的变量在内存中是这样...2015-10-23
  • C语言中free函数的使用详解

    free函数是释放之前某一次malloc函数申请的空间,而且只是释放空间,并不改变指针的值。下面我们就来详细探讨下...2020-04-25
  • C语言中计算正弦的相关函数总结

    这篇文章主要介绍了C语言中计算正弦的相关函数总结,包括正弦和双曲线正弦以及反正弦的函数,需要的朋友可以参考下...2020-04-25
  • 详解C语言中的rename()函数和remove()函数的使用方法

    这篇文章主要介绍了详解C语言中的rename()函数和remove()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25
  • C语言中求和、计算平均值、方差和标准差的实例

    这篇文章主要介绍了C语言中求和、计算平均值、方差和标准差的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-12-10
  • java中String类型变量的赋值问题介绍

    下面小编就为大家带来一篇java中String类型变量的赋值问题介绍。小编觉得挺不错的。现在分享给大家,给大家一个参考。...2016-03-28
  • C#不同类型的成员变量(字段)的默认值介绍

    虽然C#编译器为每个类型都设置了默认类型,但作为面向对象的设计原则,我们还是需要对变量进行正确的初始化。实际上这也是C#推荐的做法...2020-06-25
  • C语言的基本语法详解

    本篇文章主要讲解C语言 基本语法,这里提供简单的示例和代码来详细讲解C语言的基本语法,开始学习C语言的朋友可以看一下,希望能够给你带来帮助...2021-09-18
  • 详解ES6实现类的私有变量的几种写法

    这篇文章主要介绍了详解ES6实现类的私有变量的几种写法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-10
  • python 实现循环定义、赋值多个变量的操作

    这篇文章主要介绍了python 实现循环定义、赋值多个变量的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-09
  • C语言中send()函数和sendto()函数的使用方法

    这篇文章主要介绍了C语言中send()函数和sendto()函数的使用方法,是C语言入门学习中的基础知识,需要的朋友可以参考下...2020-04-25