C语言常见关键字:一文打尽

关键字

    • 1. 前言
    • 2. 什么是关键字
    • 3. extern-声明外部符号
    • 4. auto-自动
    • 5. typedef-类型重定义(类型重命名)
    • 6. register-寄存器
      • 6.1 存储器
      • 6.2 register关键字的作用
    • 7. static-静态
      • 7.1 static修饰局部变量
        • 7.1.1 代码对比
        • 7.1.2 原理分析
      • 7.2 static修饰全局变量
        • 7.2.1 代码对比
        • 7.2.2 原理分析
      • 7.3 static修饰函数
        • 7.3.1 代码对比
        • 7.3.2 原理分析

在这里插入图片描述

1. 前言

大家好,我是努力学习游泳的鱼。关键字,这名字一听,就很关键。而有些关键字,你可能不是很了解,更别谈使用。所以,这篇文章将带你见识常见的关键字,一起领略它们的风采吧。

2. 什么是关键字

C语言提供了丰富的关键字,这些关键字都是语言本身预先设定好的,

用户自己是不能创造关键字的。

大部分关键字会在其他章节介绍,这里仅介绍一些稍微有点难度的关键字。

3. extern-声明外部符号

extern可以用来声明外部符号,如外部的全局变量和函数。
如我们在test1.c里定义了全局变量aint a = 2022;
我们想在test2.c里使用,就得先用extern声明一下extern int a;
注意:一般extern是用来声明外部的全局变量的。因为如果直接写int a;就不是声明了,而是定义,会直接创建一个变量a。只有写extern int a;才是声明变量a。如果是声明外部的函数,可以省略掉extern。如直接写int Add(int, int);和写extern int Add(int, int);效果是相同的。

4. auto-自动

C语言里的局部变量,进入局部范围时自动创建,出局部范围时自动销毁。这种自动创建,自动销毁的特性,其实是由于前面省略了关键字auto。比如,int a = 0;其实编译器会处理为auto int a = 0;一般来说,auto会被省略掉。

5. typedef-类型重定义(类型重命名)

typedef关键字用于给类型起别名,相当于起了个外号。
比如unsigned int num = 10;如果我们嫌unsigned int这个类型写起来太麻烦了,可以给它起个别名叫做uint:typedef unsigned int uint;这样上面的代码就等价于uint num = 10;

6. register-寄存器

6.1 存储器

数据的存储,需要存储器。常见的存储器有:

网盘,硬盘,内存,高级缓存,寄存器。
从左到右,速度越快,从而造价越高,从而空间越小。

早期,CPU处理的数据都来自内存。当时,CPU的处理速度和内存的读写速度是差不多的。随着技术的迭代,内存的读写速度逐渐跟不上CPU的处理速度,CPU在很大程度上被闲置了。
于是就有了这么一层设计。在内存之上设置读写速度更快的高级缓存和寄存器。CPU从寄存器中拿数据,与此同时,寄存器从高级缓存中拿数据,高级缓存从内存中拿数据。如果CPU想要的数据在寄存器中没有,那就直接从高级缓存中拿数据,如果还没有再从内存中拿。由于大部分数据都能在寄存器中命中,整体上,处理数据的速度就提升了
以上,我们能明白一点:

寄存器的读写速度是非常快的

6.2 register关键字的作用

如果我们写int num = 10;num是放在内存中的。如果我们加了个registerregister int num = 10;此时register的作用是建议num放在寄存器中。注意只是建议,实际是否放在寄存器中取决于编译器的处理。

7. static-静态

在C语言中,static有3种用法,分别修饰局部变量,全局变量和函数

1.修饰局部变量-称为静态局部变量
2.修饰全局变量-称为静态全局变量
3.修饰函数-称为静态函数

7.1 static修饰局部变量

7.1.1 代码对比

下面代码的输出结果是多少呢?

#include <stdio.h>void test()
{int a = 5;a++;printf("%d ", a);
}int main()
{int i = 0;while (i < 10){test();i++;}return 0;
}

输出结果:10个6
为什么呢?test函数被调用了10次,每次都做了同样一件事,创建a并初始化为5a自增变成6,打印a(即6)。本质上,每次进入test函数都会创建a,出test函数时都会销毁a。这是由于局部变量的特性:进入局部范围创建,出局部范围销毁。那么,每次进入test函数创建的都是一个新的a,和之前创建的a没有任何关系。
明白这点后,再看下面这段代码,输出的结果又是多少?

#include <stdio.h>void test()
{static int a = 5;a++;printf("%d ", a);
}int main()
{int i = 0;while (i < 10){test();i++;}return 0;
}

答案:输出6~15
分析一下:第一次调用test函数时和没有static相同,创建a并初始化,自增,打印(此时a6),但第二次调用怎么就打印7了呢?这说明,第二次调用时,a还是上次调用留下来的6,才会自增变成7!也就是说,第一次调用结束后,a并没有销毁,第二次调用时依然存在。同理,第二次调用后a也没有销毁,第三次调用时a仍是第二次调用留下来的7,然后自增变成8后打印,以此类推。

static修饰局部变量的时候,局部变量就变成了静态的局部变量,出了局部的范围,不会销毁,下一次进入函数依然存在。

7.1.2 原理分析

内存可以分为:栈区,堆区,静态区,等等。
栈区存储的是局部变量,函数参数,等等。
堆区是用来动态内存开辟的,与之相关的函数有malloc,realloc,callocfree等等。
静态区存储的是静态变量和全局变量。
静态的局部变量出了作用域依然存在,是因为它是存储在静态区的。
同样存储在静态区的全局变量,生命周期也很长。

static修饰局部变量时,实际改变的是变量的存储位置,本来一个局部变量是放在栈区的,被static修饰后放在了静态区,从而导致,出了作用域依然存在,生命周期并没有结束。
注意:放在静态区的变量出了作用域不销毁,相当于生命周期变长了,但是作用域并没有发生变化,也就是说,静态的局部变量仍然只能在它的局部范围内使用!
静态区中的数据的生命周期和程序的生命周期是一致的。程序结束,静态数据的生命周期也就到了。

7.2 static修饰全局变量

7.2.1 代码对比

我们创建两个源文件,test1.ctest2.c
test1.c里定义一个全局变量g_val

// test1.c
int g_val = 2022; // 全局变量,定义在test1.c中

test2.c内部使用这个全局变量,由于全局变量的作用域是整个工程,所以可以跨源文件使用。但是在使用前需要使用extern声明,否则会报编译错误。

// test2.c
extern int g_val;int main()
{g_val = 2023;return 0;
}

如果我们在g_val的定义前面加上static会发生什么呢?

// test1.c
static int g_val = 2022; // 全局变量,定义在test1.c中// test2.c
extern int g_val;int main()
{g_val = 2023;return 0;
}

此时会报链接错误,因为g_val是定义在test1.c里的静态全局变量,不能在test2.c内部使用。看来静态的全局变量不能跨文件使用了。

7.2.2 原理分析

一个全局变量本来是具有外部链接属性的,既能在自己所在的源文件内部使用,也能在其他文件内部使用。
但是被static修饰之后外部链接属性就变成了内部链接属性,只能在自己所在的源文件内部使用,不能在其他文件内部使用了。
使用上感觉作用域变小了。

7.3 static修饰函数

7.3.1 代码对比

我们在test1.c里定义一个函数

// test1.c
int Add(int x, int y)
{return x + y;
}

test2.c内部使用,同理要先声明(此时可以省略extern),否则会报一个警告。

// test2.c
#include <stdio.h>extern int Add(int, int); // extern可以省略int main()
{int sum = Add(10, 20);printf("sum = %d\n", sum);return 0;
}

如果在函数定义前加上static会发生什么呢?

// test1.c
static int Add(int x, int y)
{return x + y;
}// test2.c
#include <stdio.h>extern int Add(int, int); // extern可以省略int main()
{int sum = Add(10, 20);printf("sum = %d\n", sum);return 0;
}

此时会报链接错误,因为Add函数是定义在test1.c内部的静态函数,不能在test2.c内部使用。看来static修饰函数和修饰全局变量类似,静态的函数也不能跨文件调用。

7.3.2 原理分析

static修饰函数的作用:一个函数本来是具有外部链接属性的,但是被static修饰之后,外部链接属性就变成了内部链接属性,这时这个函数只能在自己所在的源文件内部使用,其他文件是无法使用的。
使用上的感觉好像是作用域变小了。

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

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

相关文章

Java中常见延时队列的实现方案总结

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Java全栈-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&…

41. 【Linux教程】日志文件系统

前小节介绍了早期的 Linux 文件系统&#xff0c;本小节介绍 Linux 日志文件系统&#xff0c;日志文件系统是给 Linux 操作系统增加了一些安全相关能力&#xff0c;日志文件系统和早期的文件系统相比&#xff0c;它并不是先把数据写到中间存储设备&#xff0c;然后再写到存储设备…

2024/3/6打卡最短编辑距离---线性DP

题目&#xff1a; 给定两个字符串 A 和 B&#xff0c;现在要将 A 经过若干操作变为 B&#xff0c;可进行的操作有&#xff1a; 删除–将字符串 A 中的某个字符删除。插入–在字符串 A 的某个位置插入某个字符。替换–将字符串 A 中的某个字符替换为另一个字符。 现在请你求出&a…

springboot基于java的中医院门诊挂号诊断就诊系统ssm+jsp

主要研究内容&#xff1a; 医院门诊挂号系统分为护士&#xff0c;医生&#xff0c;药房&#xff0c;收费&#xff0c;管理员等权限。 护士&#xff1a;挂号、退号、查询病人。挂号——就诊科室(发热门诊、骨科、妇科等等)&#xff0c;就诊医生数据库获取&#xff0c;挂号类型—…

测试遍历1e5,1e8数组耗时

1e8大概0.38秒&#xff0c;即380ms 1e5耗时1ms左右&#xff1a; 代码使用方式来自&#xff1a;clock - C Reference (cplusplus.com)

Java 与 JavaScript 区别

Java 与 JavaScript 区别 制造商不同 Java 是 SUN Microsystems 公司推出的新一代面向对象的程序设计语言。javascript 是 Netscape 公司的产品&#xff0c;其目的是为了扩展 Netscape Navigator 功能&#xff0c;而开发的一种可以嵌入 Web 页面中的基于对象和事件驱动的解释…

python_读取txt文件绘制多条曲线III

先把文件中指定列&#xff0c;去重提取出来&#xff0c;然后根据指定列去匹配数据&#xff0c;最后完成多条数据的绘图&#xff1b; import matplotlib.pyplot as plt import re from datetime import datetime from pylab import mplmpl.rcParams["font.sans-serif"…

【python 1】----Pytest基础知识

定义 用于编写和执行Python测试全功能测试框架&#xff08;工具&#xff09;&#xff0c;是一个第三方库 安装 pip insatll pytest 安装pytest --version 校验 pytest的组成构成 不写调用语句也可以执行函数内容 在用例运行语句里面&#xff1a; -s:指的是开启与终端的…

vue3 setup函数与setup语法糖之间的区别

普通setup函数构建的组件 import {ref} from vueexport default {setup(){const countref(0)const handleUpdate()>{count.value}return{count,handleUpdate}}} </script>使用setup语法糖构建的组件 <script setup>import {ref} from vueconst countref(0)con…

devc++小游戏3.8.5

导航&#xff1a; Dev-c跑酷小游戏 1.0.0 devc跑酷小游戏1.2.5 devc跑酷游戏1.2.6 devc跑酷游戏2.0.0 devc跑酷游戏2.0.1 devc跑酷游戏2.4.0 devc跑酷小游戏3.5.0 更新内容 重磅回归&#xff0c;存档搞定&#xff01;&#xff01;&#xff01; 每一关需要前一关已…

C#日志记录:实现应用程序的监控与调试

日志记录是软件开发中不可或缺的功能&#xff0c;它能帮助开发者在应用程序运行时记录重要信息&#xff0c;便于调试和监控。本文将详细介绍C#中的常用日志记录功能以及常用的日志库&#xff0c;包括日志级别控制、日志输出格式、自定义日志目标、结构化日志和异步日志记录。同…

【Linux】常见指令1(ls指令、pwd指令、cd指令、touch指令、mkdir指令、rmdir指令、man指令、cp指令、mv指令、cat指令)

目录 01.ls指令与ll指令 02.pwd指令 03.cd指令 04.touch指令 05.mkdir指令 06.rmdir指令&&rm指令 07.man指令 08.cp指令 09.mv指令 10.cat指令 01.ls指令与ll指令 ls指令&#xff1a; 原型&#xff1a;list directory contents 语法&#xff1a;ls[选项][目录…

nodejs安装教程(及过程中的易错)

nodejs&#xff1a;Nodejs 是基于 Chrome 的 V8 引擎开发的一个 C 程序&#xff0c;目的是提供一个 JS 的运行环境。 npm&#xff1a;npm 是 Node Package Manager 的缩写&#xff0c;意思是 Node 的包管理系统&#xff0c;是最大的软件包仓库 下载nodejs 首先我们需要在node…

数学算法笔记

1、平方差 [蓝桥杯 2023 省 A] 平方差 - 洛谷 考虑将公式化简&#xff0c;然后看x是由什么性质的数组成&#xff0c;该题中&#xff0c;从x奇偶性质入手&#xff0c;判断x可能的组成情况。 题解&#xff1a;Welcome - Luogu Spilopelia

抖店无货源怎么做?最新玩法分享,看这篇就懂了!

我是电商珠珠 抖店一直热度很高&#xff0c;都在讲的无货源玩法&#xff0c;对于新手来说很陌生。 今天呢&#xff0c;我就来详细的讲一下抖店无货源玩法。 第一步&#xff0c;入驻 入驻的时候需要准备一张个体的营业执照&#xff0c;以及个人的身份证、银行卡。 资金的话…

C# SwinV2 Stable Diffusion 提示词反推 Onnx Demo

目录 介绍 效果 模型信息 项目 代码 下载 C# SwinV2 Stable Diffusion 提示词反推 Onnx Demo 介绍 模型出处github地址&#xff1a;https://github.com/SmilingWolf/SW-CV-ModelZoo 模型下载地址&#xff1a;https://huggingface.co/SmilingWolf/wd-v1-4-swinv2-tagg…

python-数组元素积的符号-LEETCODE

方法一&#xff1a;笨蛋方法&#xff0c;直接相乘 def arraySign(nums): sum1 for i in range(len(nums)): sumnums[i]*sum if sum>0: return 1 if sum<0: return -1 if sum0: return 0 方法二&#xff1a;判断是…

FPGA- RGB_TFT显示屏原理及驱动逻辑

下图是TFT显示屏的显示效果 该显示屏共分为 2 个版本&#xff0c;4.3 寸版本的 TFT4.3’’_V3.0 和 5.0 寸版本的 TFT5.0’’_V3.0。 两者 PCB 背板电路完全相同&#xff0c;接口脚位定义完全相同&#xff0c;接口时序完全相同&#xff0c;仅使用的显示屏 模组尺寸不同。设计两…

⭐每天一道leetcode:28.找出字符串中第一个匹配项的下标(简单;暴力解;KMP算法,有难度)

⭐今日份题目 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 示例1 输入&#xff1a;haystack &q…

Java多线程——信号量Semaphore是啥

目录 引出信号量Semaphore &#xff1f;Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 Java多线程——信号量Semaphore是啥 信号量Semaphore &#xff1f; Semaphore 通常我们叫它信号量&#xff0c; 可以用来控制同时访问特…