C 语言 - 存储类说明符

【预备知识】
1)C 语言 - 存储时期
2)C 语言 - 链接属性
3)C 语言 - 作用域

1. 分类:

· C 语言为变量提供了 5 中不同的存储模型(即存储类)。
C语言中的5种存储模型
(此外还有基于指针的第 6 种存储模型,不在本篇笔记范围内,后续补充)。
· C 语言提供了以下 5 个存储类说明符(storage-class-specifier):
auto
register
static
extern
typedef
 由于 typedef 和其他四个的语义不同,所以不在这里进行讨论。
存储类说明符

2. 自动变量 auto

自动变量具有代码块作用域、自动存储时期和空链接。
1) 默认情况下,在代码块函数头部定义的任意变量都是自动变量。
2)可以使用关键字 auto 对块作用域变量进行显式声明。

// ivar, ilen 都是自动变量
void func (int ivar) {auto int ilen = 5;// to doreturn 0;
}

· 注意不带 ‘{}’ 的代码块,比如 if 或者 while 的子句。
· 注意 auto 只能用于块作用域变量的声明。虽然函数头部定义的变量也是自动变量,但不可以使用 auto 来显式声明。
2)auto 关键字的作用:
· 显式声明该变量为自动存储模型;
· 用来有意覆盖一个外部函数定义;
3)对于自动变量,只能在变量定义所在的代码块(包含其嵌套的代码块)通过名字访问该变量。
【注意】
a. 可以用参数向其他函数传送自动变量的值和地址,但那是间接的方式。
b. 另一个代码块(包括其嵌套的代码块)可以存在同名变量,但那是存储在不同内存位置的另一个独立变量。
4)对于嵌套代码块中的同名变量,外层代码块的变量会被内层代码块中的同名变量覆盖(程序离开内层代码块时就会恢复外层代码块中的同名变量)。
5)自动变量的优点:在程序离开当前代码块时,自动变量消失了,其占用的内存可以用来做别的事情。
6)自动变量需要显式初始化!切记!
  一些编辑器会默认初始化变量,但最好自己来初始化!给变量赋初值是一个好习惯。
7)auto 关键字的实际用途?
在我查阅的大部分资料里,可以说,auto 基本是没有什么用的,因为 auto 声明了一个变量是自动变量,且 auto 只能用在代码块作用域内,但是别忘了,代码块作用域内定义的变量默认就是自动变量……这样一来,auto 的显式声明就显得十分鸡肋。
那为什么 C 语言还保留了 auto 关键字呢?(C++11 开始弃用了 auto 作为自动存储期的语义)主要是为了向后兼容,C 语言之前的代码使用 auto 来声明变量,在过去有很多代码需要移植到新的 C 语言中,在这种情况下,将关键字 auto 添加到语言中是很有帮助的。

3. 寄存器变量 register

1)通常,寄存器变量存储在速度最快的可用内存中(通常是 CPU 寄存器),目的是为了比普通变量更快地被访问和操作。
2)使用 register 声明符声明寄存器变量,该声明符只能用于块作用域的对象和函数原型作用域的对象。
3)因为寄存器变量多是存放在一个寄存器中,因此无法对一个寄存器变量进行一元取值运算(&),也不能将声明为 register 的数组转换为指针。
4)register 仅仅是一个请求而不是指令,如果没有可用的寄存器或者高速内存,那么编译器会把它当自动变量处理,即便如此依然存在 3)中的限制。
注意,虽然使用 register 修饰变量理论上可以提高效率,但不应该在程序中大量使用 register,毕竟寄存器的数量是有限的,而且将变量存储在寄存器中也会消耗一定的处理时间,反而会降低程序的运行效率。
5)使用 register 声明的类型是有限的(例如,处理器可能没有足够大的寄存器来容纳 double)。
6)register 关键字在实际开发中的用途?
很遗憾,在实际的开发中很少会用到 register 这个关键字,但这并不是因为它和 auto 一样鸡肋。早期的编译器不太善于决定是否要将机器寄存器应用于一个变量,因此 C 语言提供了 register 以便开发人员手动执行这个操作。随着技术的改进编译器变得更聪明了,在决定变量存储方面往往比开发人员做得更好(很多时候开发人员的决定只会让程序变得更慢),这就是为什么很多编译器在涉及存储时总是忽略 register
不过,使用 register 声明的变量无法进行取址操作,可以使用 register 来确保变量不会被地址访问导致变量在期望的范围之外被更改。(奇怪的思路,不建议)
7)关于寄存器的补充。
a. 寄存器存在的原因:CPU 是负责进行计算的硬件单元,为了方便运算,需要先把数据从内存读取到 CPU 内,这就要求 CPU 具有一定的数据临时存储能力,但 CPU 并不是在需要开始计算时才把特定数据读进 CPU 里面,那太慢了。 因此现代 CPU 内都集成了一组叫做寄存器的硬件,用于保存临时数据。
b. 寄存器存在的本质: 在硬件层面上提高计算机的运算效率(因为不需要反复从内存里读取数据)。

4. 具有代码块作用域的静态变量

1)静态指的是变量的地址是固定的,变量的值是可以修改的。
2)使用 static 声明代码块作用域变量具有代码块作用域的静态
【注】对于常量字符串,使用 static 是有用的,因为它减轻了频繁初始化经常调用的函数的开销。
3)具有代码块作用域的静态变量具有全局生存期(在程序载入时创建,在程序结束时销毁),但只在定义的代码块内可见。
4)作用:保存程序运行时的中间结果。

void checkNum(int ivar) {int iflag = 0;static int icnt = 0;if (ivar == iflag) {printf("Found %d %d time(s).\n", iflag, ++icnt);}

上面例子中,“int iflag = 0;” 是 checkNum() 的一部分,该语句在每次调用函数时都会执行。
但语句 “static int icnt = 0;” 实际上并不是函数 checkNum() 的一部分,该语句放在 checkNum() 函数中只是为了告诉编译器,icnt 的可见范围仅限于函数 checkNum() 的函数体内。并且它不是在运行时执行的语句(可以在调试的时候进行测试,程序会跳过这一语句)。
程序离开了 checkNum() 后并不会销毁 icnt 变量,只是这个时候变量 icnt 在外层不可见,当重新回到该函数时,可以看到该变量保持了上次离开时的状态(值和地址)。
5)不应该在结构体中声明静态变量。
C 语言要求结构体中的所有成员都放置在内存中的同一地方,即结构成员的内存分配应该是连续的,因为 struct 成员的值是通过计算元素从所在结构体的起始地址的偏移量来获取的。如果确实有需要,可以使整个结构保持静态。
(【注意】可以在函数内部(堆栈段 stack segment)声明一个 struct,或动态分配内存(堆段 heap segment),甚至可以是全局的(BSS或数据段 data segment),只要能保证内存连续。)

5. 具有外部链接的静态变量

具有外部链接的静态变量,也称为外部存储类(external storage class),外部变量(external variable)。
1)外部存储类具有文件作用域、外部链接和静态存储时期。
2)外部存储类声明在所有函数之外。
3)可以在使用外部变量的函数中通过使用 extern 关键字再次声明它,这个声明是可选的。

// assist.c
int ierrupt;	// 定义在所有函数之外的变量;
double darr[100];	// 外部定义的数组;
char cflag = 'Q';int func() {extern int ierrupt;	// 可选的声明extern double darr[];	// 可选的声明char cflag = 'q';	// 这里的 cflag 覆盖了外部的 cflag// to do return 0;
}

注意,这里 “可选的声明” 的意思是:整个声明语句是可选的。而不是声明语句中的 extern 关键字是可选的。如果在函数中声明了和外部变量同名的变量,且漏掉了 extern,那么将创建一个独立的自动变量!(比如上面例子中的 cflag
注意上面的数组 darr,不必在可选的声明中指明数组大小,因为第一次声明的时候已经提供了这一信息。
上面例子中的两句可选声明完全可以省略并且不会影响程序的逻辑。
一个建议是,在程序中(尤其是复杂的程序中)写上这句可选的声明,以提高程序的可读性。
另外,如果变量定义在别的文件中,那么必须使用 extern 来声明该变量,这个声明是必要的。

// main.c
extern char cflag;	// 必要的声明,// 因为 cflag 定义在 assist.c 中
int main() {// to doreturn 0;
}

4)不同于自动变量,外部变量在没有显示初始化的情况下,会自动赋初值 0。
a. 还是那句话,给变量赋初值是一个好习惯。
b. 一个外部变量只可以进行一次初始化,而且一定是在变量被定义的时候被初始化。(区别于赋值)

// 这个语句是错误的。
// 因为 extern 说明这是一个引用声明,
// 而非定义声明!
extern char c_permis = 'Y';	// error!!

5)只能用常量表达式来初始化文件作用域变量。
常量表达式是指在编译时可以完全确定其值的表达式
6)外部变量可以被程序的任一文件中所包含的函数使用。
外部变量不需要使用参数和指针就能完成值的传递,使用上确实方便,但这是有代价的,需要谨慎对待。因为它太不明显,可能会在不知不觉中被偷偷修改,而又很难排查。
一个建议:不要随意使用外部变量。

6. 具有内部链接的静态变量

1)具有内部链接的静态变量具有静态存储时期、文件作用域和内部链接。
2)使用 static 关键字在所有函数外部对变量进行定义。
a. 区别于上面讨论的具有外部链接的静态变量,具有内部链接的静态变量在定义的时候多了一个 static
b . extern 关键字是在引用声明时使用而不是定义时使用!!
c. 可以在函数中使用 extern 来再次声明任何具有文件作用域的变量,但这并不改变链接!链接是在定义的时候就决定的!
3)只可以被与它在同一个文件中的函数使用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/15882.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html实现蜂窝菜单

效果图 CSS样式 keyframes _fade-in_mkmxd_1 {0% {filter: blur(20px);opacity: 0}to {filter: none;opacity: 1} } keyframes _drop-in_mkmxd_1 {0% {transform: var(--transform) translateY(-100px) translateZ(400px)}to {transform: var(--transform)} } ._examples_mkmx…

uniapp小程序,根据小程序的环境版本,控制的显页面功能按钮的示隐藏

需求:根据小程序环境控制控制页面某个功能按钮的显示隐藏; 下面是官方文档和功能实现的相关代码: 实现上面需要,用到了uni.getAccountInfoSync(): uni.getAccountInfoSync() 是一个 Uniapp 提供的同步方法&#xff0c…

rsync远程同步

文章目录 一.rsync简介1.一款快速增量备份工具2.rsync应用场景2.1 rsyncinotify的应用场景2.2 rsynccron的应用场景 二.配置rsync备份源(同步方式)1.rsync同步源2.同步方式3.备份的方式 三.常用rsync命令1.基本格式2.常用选项3.配置源的两种表达 四.配置…

Android 面试题 内存泄露的原因 二

🔥 什么是内存泄漏 🔥 在Android开发过程中,当一个对象已经不需要再使用了,本该被回收时,而另个正在使用的对象持有它引用从而导致它不能被回收,这就导致本该被回收的对象不能被回收而停留在堆内存中&#…

SQL-每日一题【626.换座位】

题目 表: Seat 编写SQL查询来交换每两个连续的学生的座位号。如果学生的数量是奇数,则最后一个学生的id不交换。 按 id 升序 返回结果表。 查询结果格式如下所示。 示例 1: 解题思路 前置知识 MySQL 的 MOD() 函数是取模运算的函数,它返回两个数相除…

【自用记录】常见的第三方接口加密签名方式(ASCll码字典序、URL键值对、 SHA-256加密、MD5加密)

案例1: 案例2: 以上第三方接口都用类似的加密签名方式,两者有类似的部分: 方案1的: $kdata = array(parkId=>$parkId,ts => $ts,serviceCode=>getParkingPaymentList,reqId => $reqId,plateNo => $car_code,//车牌 可为空pageIndex => 1,//第几页page…

无涯教程-jQuery - innerHeight( )方法函数

innerHeight()方法获取第一个匹配元素的内部高度(不包括边框&#xff0c;包括填充)。 innerHeight( ) - 语法 selector.innerHeight( ) innerHeight( ) - 示例 以下是一个简单的示例&#xff0c;简单说明了此方法的用法- <html><head><title>The jQuery…

适合做笔记的软件有哪些?8款好用强大的笔记软件推荐!

除了Goodnotes和Notability&#xff0c;你还知道哪些值得推荐的免费笔记软件吗&#xff1f;本文结合自己的使用经验&#xff0c;推荐笔记软件的同时&#xff0c;亦推荐一些不错的绘图软件供大家选择使用。 1.OneNote 基本的笔记功能都有&#xff0c;加粗、倾斜、下划线、突…

TPlink云路由器界面端口映射设置方法?快解析内网穿透能实现吗?

有很多网友在问&#xff1a;TPlink路由器端口映射怎么设置&#xff1f;因为不懂端口映射的原理&#xff0c;所以无从下手&#xff0c;下面小编就给大家分享TPlink云路由器界面端口映射设置方法&#xff0c;帮助大家快速入门TP路由器端口映射设置方法。 1.登录路由器管理界面&a…

高等数学中如何求间断点

高等数学中求间断点是一项重要的技巧&#xff0c;特别适用于分析函数的性质和图像的特征。在本文中&#xff0c;我们将深入探讨如何在给定函数中找到间断点&#xff0c;并解释其数学原理和实际应用。 什么是间断点&#xff1f; 在高等数学中&#xff0c;间断点是指函数在某个点…

【C++从0到王者】第十四站:list基本使用及其介绍

文章目录 一、list基本介绍二、list基本使用1.尾插头插接口使用2.insert接口使用3.查找某个值所在的位置4.erase接口使用以及迭代器失效5.reverse6.sort7.merge8.unique9.remove11.splice 三、list基本使用完整代码 一、list基本介绍 如下所示&#xff0c;是库里面对list的基本…

pytorch学习——正则化技术——权重衰减

一、概念介绍 权重衰减&#xff08;Weight Decay&#xff09;是一种常用的正则化技术&#xff0c;它通过在损失函数中添加一个惩罚项来限制模型的复杂度&#xff0c;从而防止过拟合。 在训练参数化机器学习模型时&#xff0c; 权重衰减&#xff08;weight decay&#xff09;是…

消防应急照明设置要求在炼钢车间电气室的应用

摘 要:文章以GB51309—2018《消防应急照明和疏散指示系统技术标准》为设计依据&#xff0c;结合某炼钢车间转炉项目的设计过程&#xff0c;在炼钢车间电气室的疏散照明和备用照明的设计思路、原则和方法等方面进行阐述。通过选择合理的消防应急疏散照明控制系统及灯具供配电方案…

国内办公协作系统评测:5 款软件推荐

办公协作系统是现代信息化办公的必备工具之一&#xff0c;对于企业来说&#xff0c;选择一款好用的办公协作系统非常重要。然而&#xff0c;在众多的办公协作系统中&#xff0c;哪个好用是一个让人头痛的问题。总体而言&#xff0c;国内的办公协作系统已经相当成熟和完善&#…

golang interface类型的nil

golang中interface变量&#xff0c;底层两个对象来存&#xff0c;一个是type、一个是value&#xff0c;只有type、value都为nil时&#xff0c;interface变量才是nil package mainimport ("fmt""reflect" )type People interface {Show() }type Student str…

ALLEGRO之Logic

本文主要讲述ALLEGRO的Logic菜单。 &#xff08;1&#xff09;Net Logic&#xff1a;暂不清楚&#xff1b; &#xff08;2&#xff09;Net Schedule&#xff1a;暂不清楚&#xff1b; &#xff08;3&#xff09;AssignDifferential Pair&#xff1a;暂不清楚&#xff1b; &a…

layui框架学习(35:数据表格_列参数设置)

Layui中的table数据表格模块支持对表格及列进行基础参数设置以提高数据的可视化及可操作性&#xff0c;本文学习并记录与列相关的主要基础参数的用法及效果。   基础参数field设置待显示到列中的数据的字段名&#xff0c;主要针对数据表格url属性中返回的数据集合或data属性设…

《向量数据库指南》——Milvus Cloud 2.3 和 2.4 版本的重要变化

Milvus Cloud2.3 和 2.4 版本的重要变化。 首先是 Milvus Cloud2.3 将支持 Json 数据类型,在此基础上亦会支持 Schemaless。此前,用户在使用 Milvus Cloud的过程中会先定一个静态 Schema,此时,如果在实际业务层面如果多了几个 feature 或者 Metadata,就意味着数据需要重新…

echarts柱状图横坐标文字过长的解决办法

背景&#xff1a;echarts图中横坐标显示的文字过长&#xff0c;导致字都堆积在一块如下图所示 解决办法 一&#xff1a;可以尝试修改‘axisLabel’的‘rotate’和‘interval’参数&#xff0c;‘rotate’参数可以设置标签的旋转角度&#xff0c;可以避免标签之间的重叠&#x…

uni-app之微信小程序实现‘下载+保存至本地+预览’功能

目录 一、H5如何实现下载功能 二、微信小程序实现下载资源功能方面与H5有很大的不同 三、 微信小程序实现文件&#xff08;doc,pdf等格式&#xff0c;非图片&#xff09;下载&#xff08;下载->保存->预览&#xff09;功能 四、图片预览、保存、转发、收藏&#xff1…