C语言深度剖析:关键字

news2024/11/23 21:47:27

C语言深度剖析:关键字

  • C语言深度剖析:关键字
    • 前言
    • 定义与声明(补充内容)
    • 最宏大的关键字-auto
    • 最快的关键字-register
    • 关键字static
    • 被冤枉的关键字-sizeof
    • 整型在内存中的存储
      • 原码、反码、补码
      • 大小端补充
      • 理解变量内容的存储和取出
      • 为什么都是补码
      • 整型取值范围
    • 关于if判断的问题
    • bool变量
      • bool变量和零值的比较
    • float类型数据的比较
      • float变量与零值的比较
      • 不安全函数问题
    • switch语句的小细节
    • 三大循环中的细节
    • 打破对goto语句的偏见
    • void的一些细节
      • void*的运算操作
    • 关于return的细节
      • return怎样将值返回
    • const使用的几种场景
      • const修饰普通变量
      • const修饰数组
      • const修饰指针
      • const修饰函数
    • volatile-最易变的关键字
    • struct关键字
      • 柔性数组
    • union关键字
    • enum枚举类型
    • typedef关键字
      • typedef和#define宏的区别
    • 总结
      • 数据类型关键字12个
      • 控制语句关键字12个
      • 存储类型关键字5个
      • 其他关键字3个

C语言深度剖析:关键字

前言

本篇内容既是对之前C语言学习的重点复习内容,也是对之前内容的补充,大体内容逻辑参考了《C语言深度解剖》这本书,所以这节内容更像是个对C语言学习的一个重点内容复盘,也就是将C语言重点知识重新串一遍,同时也对之前一些掌握不太好的知识的补充。所以下面几乎都是一个一个的知识点,友情提示:不是很适合零基础的同学。基础不太好的请将C语言的基础内容部分系统进行学习。

主要将C89/C99标准的主要的32个关键字整体上来总结复习一遍就是我们的目的

image-20230227104829428

定义与声明(补充内容)

1.程序运行,需要加载到内存中

2.程序计算,需要使用变量

定义变量的本质:在内存中开辟一块空间,用来保存数据。

变量声明:extern关键字,声明一个变量或函数已经存在,可以改变其作用域。

变量初始化与赋值:

变量的初始化:在为变量开辟空间的同时将数据存放进去

变量的赋值:将数据放入已经开辟好的空间里面

最宏大的关键字-auto

auto这个关键字是只能用来修饰局部变量的,意思就是表示局部变量只能在其所在的代码块内有效,出代码块则销毁。也就是限制了局部变量的生命周期,auto已经是一个非常原始的关键字了,由于现在编译器已经很智能的解决这些了,所以已经不再需要它了。

最快的关键字-register

register:建议将变量放入寄存器中

那么什么样的变量,可以采用register呢?

1.局部的(全局会导致CPU寄存器被长时间占用)

2.不会被写入的(写入就需要写回内存,后续还要读取检测的话,register的意义在哪呢?)

3.高频被读取的(提高效率所在)

4.如果要使用,请不要大量使用,因为寄存器数量有限

关键字static

修饰全局变量:只能在文件内部使用,改变了作用域

修饰局部变量:相当于改变了声明周期

修饰函数:只能在文件内部使用,相当于改变了作用域

被冤枉的关键字-sizeof

首先记住sizeof不是函数,不是函数,不是函数!!!

三种写法:

sizeof(int)
sizeof(a)
sizeof a

sizeof(i++)内部i不会自增。

整型在内存中的存储

原码、反码、补码

C语言操作符大全

在讲操作符时有详细说明,不再赘述。

原反补码的知识点

大小端补充

数据低位放在低地址处则为小端,口诀小小小。不符合则为大端。

理解变量内容的存储和取出

数据存入时和类型无关,存入二进制即可,取出时才看类型。

为什么都是补码

计算机在存储数据都是二进制,原因:

1.CPU内只集成了加法器,只有补码才能解决减法问题。

2.补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

整型取值范围

记住char类型有符号-128~127,无符号0 ~255(理解怎么计算)。

类型的取值范围计算

关于if判断的问题

例如语句:if(flag==1),从正常逻辑上来讲我们通常想的是如果flag==1,则…,但是实际上如果更系统地来描述的话,应该是

先计算括号内的表达式逻辑值,然后进行判断。

bool变量

布尔变量,C99中引入的概念,由于我们目前仍主要按C89/C90标准,所以使用并不多,但是不能一口咬死C语言没有bool类型。

_Bool就是一个类型,不过在新增头文件stdbool.h中,被重新用宏写成了bool,为了保证C/C++兼容性 。

bool a=0;sizeof(a);可以求出布尔变量的大小,理论上来讲表示真假一个字节就可以,但是具体还是取决于编译器。

image-20230219200819553

但是还有一个全部大写的BOOL,TRUE,FALSE,

image-20230219200958812

这是在VS中看到的源文件,微软自己搞出的一套定义,不要使用,为了保证代码的可移植性。

bool变量和零值的比较

bool变量与零值的比较有多种方法,例如if(pass==true);if(pass= =0);if(pass= =false);(pass为一个布尔变量),但是这样的写法都不推荐,我们推荐以下两种写法:

if(pass)if(!pass);

float类型数据的比较

关于浮点型数据存储的细节不再赘述,链接:C进阶:数据在内存中的存储

很多浮点型数据在内存中不能够精确存储,因此一定不能将两个浮点数直接比较,例如if(a==0.2),这是绝对不能正确判断的,正确判断两个浮点数存储的方式是定义一个宏EPS,假设为0.0000001,如果fabs((a-0.2))<EPS,fabs是一个函数取绝对值,意思就是只要差值在一定范围内则视为相等。下面举一个完整的代码例子:

#define EPS 0.00000000001
#include <math.h>
#include <float.h>
int main()
{
	float a = 3.14f;
	/*第一种写法*/
	if (fabs(a - 3.1) > EPS)
	{
		printf("you can see me!\n");
	}
	/*第二种写法*/
	if ((a - 3.1) > DBL_EPSILON)
	{
		printf("you can see me!\n");
	}
	return 0;
}
image-20230219202443314

其中DBL_EPSILON是一个很小的正数,一般用来判断比较浮点数。

float变量与零值的比较

有了上面基础就很好理解了,float变量与零值的比较就相当于:

if(fabs(x-0.0)<DBL_EPSILON)if(fabs(x)<DBL_EPSILON)即可。

不安全函数问题

两种解决方法:

#define  _CRT_SECURE_NO_WARNINGS 1//(注意必须要放在头文件之前)
#pragma warning(disable: 4996)

switch语句的小细节

image-20230220110300084

case后面的语句中可以多语句但是不可以定义变量,如果一定有需求的话,封装成一个函数。

三大循环中的细节

do while循环(注意最后分号不能省略);for循环;while循环。

三种循环中的break作用一致,都是跳出循环。

重点注意for循环中的continue是跳过本次循环到条件调整处,而在while和do while循环都是continue直接跳到条件判断处。

打破对goto语句的偏见

在市面上几乎所有的书里面都会有不建议使用goto语句,实际上很多公司内部的代码规范也是命令禁止使用goto语句,但是goto语句绝对不仅仅是毫无用处,不推荐使用goto语句仅仅是因为很多实力程度不够的程序员使用会造成逻辑混乱,很容易出错,但是在一些大型工程里面goto语句也是非常重要的一部分。例如:

image-20230220205219720

这是Linux内核中的部分源代码,可以看到其实goto语句是使用非常频繁的,如果你要用工具去数一下数量的话可能达到几十万行。

所以goto语句不是炸弹,仅仅是因为我们的公司当前的业务逻辑并不复杂。

void的一些细节

定义变量的本质:开辟空间

而void作为空类型,理论上是不应该开辟空间的,即使开了空间,也仅仅作为一个占位符看待

所以,既然无法开辟空间,那么也就无法作为正常变量使用,既然无法使用,编译器干脆不让他定义变量。

在vs2013中,sizeof(void)=0

在Linux中,sizeof(void)=1(但编译器依旧理解成,无法定义变量)

所以不要一口咬死sizeof(void)大小一定是0,这个是没有明确标准规定的。

自定义函数的默认返回值是int,函数返回值使用void时也不可以不写返回值,

没有返回值,如果不写void,会让阅读你代码的人产生误解:他是忘了写,还是想默认int?

在函数参数部分不写void的话就是明确指定不能给函数传参数

void*的运算操作

在vs中对void*的变量是不允许的,例如++

int main()
{
    void *p = NULL;
    p++; //报错
    p += 1; //报错
    return 0;
}  

而在gcc编译器下编译就是能通过的,由于编译器对void的大小认定不一致导致了这样的现象。

Linux 上可用的 C 编译器是 GNU C 编译器,它建立在自由软件基金会的编程许可证的基础上,因此可以自由发布。 GNUC 对标准 C 进行一系列扩展,以增强标准 C 的功能 。

关于return的细节

在使用上:由于函数在栈上开辟空间,在出函数后函数内的临时变量也会释放(并没有销毁数据,而是将数据设置为无效数据,之后使用直接覆盖),不要返回函数内部创建的指针,在后续使用是非法访问

return怎样将值返回

image-20230223155051077

可以看到,是通过一个寄存器来实现的,所以当我们写函数有返回值但是不return的话,这次函数的返回值依旧在寄存器中,当下次使用时,有可能出现一些意想不到的错误。

const使用的几种场景

const修饰普通变量

变量直接为不可直接修改的值,没什么好说的。

const修饰数组

const arr[]={1,2,3,4,5};

数组中的每一个元素都不可直接被修改。

const修饰指针

image-20230223173531257

只需要看const修饰谁即可。

const修饰函数

const修饰函数参数,函数参数不可直接被修改

const修饰函数返回值,函数返回值不可直接被修改

volatile-最易变的关键字

volatile这个关键字可以说是个非常冷门的关键字,很多人甚至都没有听说过,或者听说过但是也没有用过,今天我就详细来解释一下这个关键字

volatile这个关键字其实作用有些特殊,

总结来说作用是:防止内存被覆盖,保证内存的可见性

我们用下图来理解:

image-20230225174843308

那么这个现象怎么验证呢?

我们可以在linus环境下用gcc编译器详细看到,

验证过程:

gcc test.c -O2 -g //以O2级别进行代码优化
objdump -S -d a.out > a.s //对形成的a.out可执行程序进行优化  

image-20230225181939108

image-20230225181957956

const volatile int a = 10;  

这句代码看起来怪怪的,但其实是可以编过去的。

const要求你不要进行写入就可以。volatile意思是你读取的时候,每次都要从内存读。两者并不冲突。

虽然volatile就叫做易变关键字,但这里仅仅是描述它修饰的变量可能会变化,要编译器注意,并不是它要求对应变量必须变化!这点要特别注意。

可能有人会疑惑的是我在死循环的过程中变量怎么可能改变呢?

这是因为我们目前写的程序都是单进程,如果有多进程的程序的话,变量的值是有可能改变的。

struct关键字

基本知识不再废话,重要要注意结构体的大小计算问题,结构体内存对齐

注意一个空结构体问题,在VS下是不被允许定义的,但是在Linux中gcc环境下是可以的,计算大小为0

柔性数组

柔性数组在C99中才有,但是大多编译器对C99标准支持并不完全,所以不再过多的赘述,细节请看:

自定义类型:结构体、枚举、联合体

union关键字

需要重点理解的就是联合体在内存中的保存,经典问题:如何用程序确认当前系统的存储模式

还有个位域的问题,但是不太重要,详情见上=链接自定义类型:结构体、枚举、联合体

enum枚举类型

详情见上链接:自定义类型:结构体、枚举、联合体

typedef关键字

1.对一般类型进行重命名

2.对结构体类型进行重命名

3.对指针进行重命名

4.对复杂结构进行重命名(数组类型为例,先不要搞那么复杂

typedef和#define宏的区别

#define定义的宏只是简单的文本替换

而typedef定义了一个全新的变量

对比:image-20230227102238168

总结

以上就是所有的32个关键字总结,可能关键字并不是详细,但是还是那句话,这节更是对C语言知识的复盘,一个查漏补缺的过程。

数据类型关键字12个

char :声明字符型变量或函数
short :声明短整型变量或函数
int : 声明整型变量或函数
long :声明长整型变量或函数
signed :声明有符号类型变量或函数
unsigned :声明无符号类型变量或函数
float :声明浮点型变量或函数
double :声明双精度变量或函数
struct :声明结构体变量或函数
union :声明共用体(联合)数据类型
enum :声明枚举类型
void :声明函数无返回值或无参数,声明无类型指针

控制语句关键字12个

循环控制(5个)

for :一种循环语句
do :循环语句的循环体
while :循环语句的循环条件
break :跳出当前循环
continue :结束当前循环,开始下一轮循环

条件语句(3个)

if : 条件语句
else :条件语句否定分支
goto :无条件跳转语句

开关语句 (3个)

switch :用于开关语句
case :开关语句分支
default :开关语句中的“其他”分支

返回语句(1个)

return :函数返回语句(可以带参数,也看不带参数)

存储类型关键字5个

存储类型关键字(5个)

auto :声明自动变量,一般不使用
extern :声明变量是在其他文件中声明
register :声明寄存器变量
static :声明静态变量
typedef :用以给数据类型取别名(但是该关键字被分到存储关键字分类中,虽然看起来没什么相关性)

注意:存储关键字,不可以同时出现,也就是说,在一个变量定义的时候,只能有一个

例如:auto static int a这是绝对错误的

其他关键字3个

其他关键字(3个)

const :声明只读变量
sizeof :计算数据类型长度
volatile :说明变量在程序执行中可被隐含地改变

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

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

相关文章

多线程的初识和创建

✨个人主页&#xff1a;bit me&#x1f447; ✨当前专栏&#xff1a;Java EE初阶&#x1f447; ✨每日一语&#xff1a;知不足而奋进&#xff0c;望远山而前行。 目 录&#x1f4a4;一. 认识线程&#xff08;Thread&#xff09;&#x1f34e;1. 线程的引入&#x1f34f;2. 线程…

【计算机网络:自顶向下方法】Chapter4 网络层:数据平面

Chapter44.1 网络层概述4.1.1 网络层服务4.1.2 网络层的主要功能转发&#xff08;局部&#xff09;路由选择&#xff08;全局&#xff09;4.1.3 控制平面和数据平面传统方式SDN方式4.1.4 网络服务模型4.2 路由器组成4.2.1 路由器结构概况4.2.2 转发方式4.2.3 输入端口处理与基于…

什么是api应用程序接口?

API:应用程序接口(API:Application Program Interface) 应用程序接口是一组定义、程序及协议的集合&#xff0c;通过 API 接口实现计算机软件之间的相互通信。API 的一个主要功能是提供通用功能集。程序员通过调用 API 函数对应用程序进行开发&#xff0c;可以减轻编程任务。…

【华为OD机试模拟题】用 C++ 实现 - TLV 编码(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明TLV 编码题目输入输出描述示例一输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看…

大数据技术之Hadoop

第1章 Hadoop概述1.1 Hadoop是什么1.2 Hadoop发展历史&#xff08;了解&#xff09;1.3 Hadoop三大发行版本&#xff08;了解&#xff09;Hadoop三大发行版本&#xff1a;Apache、Cloudera、Hortonworks。Apache版本最原始&#xff08;最基础&#xff09;的版本&#xff0c;对于…

模型类的编写有没有什么靠谱的优化方法?

模型类的编写需要私有属性&#xff0c;setter...getter...方法、toString方法 和构造函数。虽然这些内容不难&#xff0c;同时也都是通过IDEA工具生成的&#xff0c;但是过程还是必须得走一遍&#xff0c;那么对于模型类的编写有没有什么优化方法?可以通过Lombok来实现优化。L…

C语言--指针进阶2

目录前言函数指针函数指针数组指向函数指针数组的指针回调函数前言 本篇文章我们将继续学习指针进阶的有关内容 函数指针 我们依然用类比的方法1来理解函数指针这一全新的概念&#xff0c;如图1 我们用一段代码来验证一下&#xff1a; int Add(int x, int y) {return xy;…

idea报错idea start filed

今天遇到idea启动失败的问题 问题分析&#xff1a; address already in use&#xff1a;bind idea需要的端口被占用 解决 重启就行&#xff0c;重启会重新分配端口。 官方解决 查看给的网站地址&#xff0c;这里官方给出的原因&#xff08;访问好慢&#xff0c;搭梯子我才…

图节点嵌入相关算法学习笔记

引言 本篇笔记为coggle 2月打卡任务&#xff0c;正好也在学习cs224w&#xff0c;干脆就一起做了&#xff0c;以下是任务列表&#xff1a; 任务名称难度任务1&#xff1a;图属性与图构造低、1任务2&#xff1a;图查询与遍历低、2任务3&#xff1a;节点中心性与应用中、2任务4&…

Spark计算框架入门笔记

Spark是一个用于大规模数据处理的统一计算引擎 注意&#xff1a;Spark不仅仅可以做类似于MapReduce的离线数据计算&#xff0c;还可以做实时数据计算&#xff0c;并且它还可以实现类似于Hive的SQL计算&#xff0c;等等&#xff0c;所以说它是一个统一的计算引擎 既然说到了Spar…

js 拖动--动态改变div的宽高大小

index.html 如下&#xff1a;&#xff08;可以新建一个index.html文件直接复制&#xff0c;打开运行&#xff09; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta http-equiv"X-UA-Compatible&qu…

Python tkinter -- 第18章 画布控件之窗口

18.2.22 create_window(position, **options) 可以在画布控件中放置其他tkinter控件。放置的方法就是使用窗口组件。一个窗口组件只能容纳一个控件。如果要放置多个控件&#xff0c;可以把这些控件作为Frame控件的子控件&#xff0c;将Frame控件放入窗口组件中&#xff0c;就可…

超简单 华为OD机试用Python实现 -【踢石头子,踢石子问题】(2023-Q1 新题)

华为OD机试题 华为OD机试300题大纲踢石头子,踢石子问题题目输入输出示例一输入输出Python 代码如下所示算法思路华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.csdn.net/hihell/categ…

ChatGPT似乎有的时候并不能搞懂Java的动态分派,你懂了吗?

目录 碎碎念 ChatGPT 中出现的问题 那么正确答案应该是什么呢&#xff1f; 分派的相关知识点总结&#xff1a; 分派是什么&#xff1f; 静态分派与动态分派&#xff1a; Java语言是静态多分派&#xff0c;动态单分派的&#xff1b; 静态分派&#xff1a;静态重载多分派…

追梦之旅【数据结构篇】——详解C语言实现二叉树

详解C语言实现二叉树~&#x1f60e;前言&#x1f64c;什么是二叉树&#xff1f;二叉树的性质总结&#xff1a;整体实现内容分析&#x1f49e;1.头文件的编写&#xff1a;&#x1f64c;2.功能文件的编写&#xff1a;&#x1f64c;1&#xff09;前序遍历的数值来创建树——递归函…

IGKBoard(imx6ull)-Input设备编程之按键控制

文章目录1- input子系统介绍2- input事件目录&#xff08;1&#xff09;struct input_event 结构体&#xff08;2&#xff09;type&#xff08;事件类型&#xff09;&#xff1a;&#xff08;3&#xff09;code&#xff08;事件编码&#xff09;&#xff08;4&#xff09;value…

【华为OD机试模拟题】用 C++ 实现 - 九宫格按键输入(2023.Q1)

最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明九宫格按键输入题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高…

webp格式转换成png怎么转

相对于png 图片&#xff0c;webp比png小了45%&#xff0c;但是缺点是你压缩的时候需要的时间更久了&#xff1b;优点是体积小巧&#xff1b;缺点是兼容性不太好, 只有opera,和chrome支持&#xff0c;不仅如此在后期的编辑修改上也很多软件无法打开。所以我们通常要将webp格式转…

9.1 IGMPv1实验

9.4.1 IGMPv1 实验目的 熟悉IGMPv1的应用场景掌握IGMPv1的配置方法实验拓扑 实验拓扑如图9-7所示&#xff1a; 图9-7&#xff1a;IGMPv1 实验步骤 &#xff08;1&#xff09;配置IP地址 MCS1的配置 MCS1的IP地址配置如图9-8所示&#xff1a; 图9-8&#xff1a;MCS1的配置 …

xgboost学习-XGBoost的智慧

文章目录一、选择弱评估器&#xff1a;重要参数booster二、XGB的目标函数&#xff1a;重要参数objective三、求解XGB的目标函数四、参数化决策树 alpha&#xff0c;lambda五、寻找最佳树结构&#xff1a;求解 ω与T六、寻找最佳分枝&#xff1a;结构分数之差七、让树停止生长&a…