C语言 | 【耗费一夜总结三本C语言系列】之 作用域 在也不用担心分不清变量的作用域拉!!!

前言

本章内容总结了作用域,分别对作用域、链接、存储期、存储类型进行概况。

在这里插入图片描述


C语言 | 快速了解C的发展史🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 指针、数组 一文透彻~~~🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 结构体、联合、枚举🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 声明🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 作用域 在也不用担心分不清变量的作用域拉!!!🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 编译步骤 会用C还不知道C如何编译???🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 数据类型总结🧡💛💚💙
C语言 | 【耗费一夜总结三本C语言系列】之 位及进制的用法🧡💛💚💙


一、数据存储🤷‍♂️

众所周知,数据存储在内存中。C的强大之处能够让程序员通过内存管理系统中指定变量的作用域和生命周期。从硬件角度来看,每个值都需要占用一定的物理内存。

  • 而在C中一块内存则被称为对象。该对象可被存储一个、多个、甚至没有存储值;
  • 标识符(a)可用来访问对象的内容int a = 10
  • 存储期描述了对象在内存的保存的时间;
  • 作用域和链接描述标识符,具有多种情况:
    作用域:
    • 多文件共享;
    • 特定文件;
    • 特定函数;
    • 函数的某部分;

二、存储类别🙋‍♂️

2.1 作用域

用于描述程序中标识符可被访问的区域;可以说标识符声明的位置决定了它的作用域

几种作用域

  • 块作用域;
  • 函数作用域;
  • 函数原型作用域;
  • 文件作用域;
2.1.1 块作用域

范围:在代码块声明的起始位置到块结尾;

  • 局部变量都具有块作用域;

什么是块:位于一对花括号之间,或者函数中任意的复合语句

拓展

C99以前,块作用域的变量都必须声明在块的开头。而C99允许了在块中任意位置声明变量;

// C99前使用for循环
int i;
for(i=0; i<10; ++i)
	...

// C99修订后
for(int i=0; i<10; ++i)
	...

该特性不仅仅在for循环,也应用到了while等各种语句。

举个栗子🌰:

以下标记中的变量都为块作用域

在这里插入图片描述

注意

应尽量避免在嵌套代码块中出现相同的变量名。为什么编译器可以把不同代码块的变量存储域同一个内存地址呢?若不是嵌套的代码块有且仅有一个代码块处于活动状态,它们的作用域无重叠状态,且变量不能同时存在,也不会同时存在。

2.1.2 函数作用域

范围:一个标签出现,直至函数结束,且为了防止混淆,标签尽量是唯一的;

  • 只适用于goto语句标签;
2.1.3 函数原型作用域

范围:从形参定义到原型声明结束;

  • 只适用于函数原型中的形参名,使用时无需与声明中的形参名匹配;
  • 类型重要,形参名可省略,但变长数组的形参名需要;

在这里插入图片描述

2.1.4 文件作用域(全局变量)

范围:从定义开始到文件末尾;

  • 定义在代码块之外的变量,且函数名也有具有文件作用域;

2.2 链接🧝‍♂️

标识符的作用域链接属性相关;

几种链接属性

  • 外部链接【extern】;
  • 内部链接;
  • 无链接
2.2.1 外部链接【全局作用域】

可在多个源文件内使用,标识符不论在几个源文件内被声明多少次都属于一个实体;

  • 一般使用extern用于外部链接,在使用其他源文件时,需声明,便于解读;
  • 当extern的标识符,可使用static来改变它的链接属性;

案例
test.h

int x = 10;

main.cpp

/*----------------------------------------------------------------------
	> File Name: test.cpp
	> Author: Jxiepc
	> Mail: Jxiepc
	> Created Time: Wed 20 Oct 2021 12:49:44 PM CST
----------------------------------------------------------------------*/

#include<iostream>
#include<unistd.h>
#include<cstring>
#include "test.h"

extern int x;

void test01(){
	int x = 1;
	std::cout << "不加extern " << x << std::endl; 	
}

void test02(){
	std::cout << "直接使用 "<< x << std::endl;
}

void test03(){
	extern int x;
	std::cout << "函数内在使用extern " << x << std::endl;	
}

int main(int argc, char *argv[]){
	
	test01();
	test02();
	test03();

	return 0;
}

运行结果:

在这里插入图片描述

2.2.2 内部链接【文件作用域】

该链接属性的变量只能在一个翻译单元内使用;在同一个源文件内所有声明都指向一个实体,位于不同源文件则分属于不同实体。

  • 一般使用static用于内部链接;
  • extern无法改变static的链接属性;

翻译单元

即一个源文件和它所包含的头文件

2.2.3 无链接

具有块作用域、函数作用域、函数原型作用域的变量都属于无链接变量;

2.3 存储期🧙‍♂️

描述了标识符访问的对象的生存期;

几种存储期

  • 静态存储期;
  • 线程存储期;
  • 自动存储期;
  • 动态分配存储期;
2.3.1 静态存储期

存在周期:程序执行期间直至程序结束;

  • 文件作用域具有静态存储器;
  • 此处的静态与static不为同一类别;
  • 静态存储期包括了内部链接外部链接所有的文件作用域变量;
  • 块作用域也可以有静态存储期;
2.3.2 线程存储期

存在周期:从被声明到线程结束;

  • 可使用_Thread_local即可获得变量的私有备份;
2.3.3 自动存储期

存在周期:当一个变量在块内声明,到块结束时,该变量会自动释放内存。

  • 当该变量释放后,其内存地址可继续被使用;
  • 块作用域(局部变量)一般都有自动存储期;
  • 变长数组较为特殊,存储期是从声明到块的末尾;

2.4 变量🧚‍♂️

几种变量

  • 自动变量;
  • 寄存器变量;
  • 块作用域的静态变量;
  • 外部链接的静态变量;
  • 内部链接的静态变量;

2.5 存储类型🙇‍♂️

2.5.1 自动变量
  • 即块作用域【自动存储期、无链接】中的变量;
  • 内层块会隐藏外层块的定义;
2.5.2 寄存器变量

通常变量都保存在内存当中,而寄存器变量则存储在CPU的寄存器中,更加高效。

  • 寄存器的地址无法获取
  • 其变量与自动变量几乎一致
  • 具有静态存储期;
  • 可声明为register的数据类型有限,例如double由于没有足够大的空间;
  • 使用只需在声明的时候加上register关键字;
2.5.3 块作用域【局部】的静态变量

此处的静态应理解为该变量再内存中的地址不改变,值可变;

  • static变量不能使用在形参中;
  • 内部静态存储类别

函数块内使用static

/*----------------------------------------------------------------------
	> File Name: test.cpp
	> Author: Jxiepc
	> Mail: Jxiepc
	> Created Time: Wed 20 Oct 2021 01:28:11 PM CST
----------------------------------------------------------------------*/

#include<iostream>
#include<unistd.h>
#include<cstring>

int test01(){
	static int a = 10;
	
	return a;	
}

int main(int argc, char *argv[]){
	int x = test01();
	std::cout<< x << std::endl;

	return 0;
}

由于变量在函数结束后即释放,所以无法将变量返回【有些编译器有优化,能够成功返回。如果将该变量多打印几次即会出错】。为了解决该问题,即可在变量声明前加上static关键字,保证了函数结束后,该变量不会被释放。

2.5.4 外部链接的静态变量

外部变量,可在其他文件中进行访问;

  • 外部变量具有静态存储期,即直至函数结束;
  • 具有文件作用域、外部链接、静态存储期;
  • 为外部存储类别;
  • 在其他文件使用时,必须使用extern进行声明;
  • 若外部变量没有被初始化,则会被初始化为0;
2.5.5 内部链接的静态变量

只属于一个文件内部使用,定义在文件开头,直至文件结束;

  • 具有静态存储期,文件作用域和内部链接;
  • 可使用extern在函数内部对其声明,但不会修改它的链接属性;

小结

  • 程序运行时变量存储的位置在以下三个:
    • 普通内存;
    • 运行时堆栈;
    • 硬件寄存器;
  • 不属于堆栈的变量 - 静态变量;
  • 静态变量与外部变量未初始化则会被自动初始化为0;
  • 存储类别说明符:auto、register、static、_Thread_local、typedef;

test.h

int x;

main.cpp

/*----------------------------------------------------------------------
	> File Name: test.cpp
	> Author: Jxiepc
	> Mail: Jxiepc
	> Created Time: Wed 20 Oct 2021 01:28:11 PM CST
----------------------------------------------------------------------*/

#include<iostream>
#include "test.h"

static int a;
extern int x;


int main(int argc, char *argv[]){

	std::cout << "静态变量: " << a << std::endl;
	std::cout << "外部变量: " << x << std::endl; 


	return 0;
}

结果
在这里插入图片描述

2.6 归纳表🧅

变量类型声明位置是否于堆栈作用域若声明static
全局所有代码块之外从声明到文件尾其他源文件无法访问
局部代码块起始处整个代码块不存于堆栈,直至程序结束
形式参数函数头部整个函数不允许

请添加图片描述

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Jxiepc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值