计算机是怎么读懂C语言的?(中)

简介: C语言预处理符号

预处理

预处理阶段会进行对头文件的包含,对于用#define定义的符号进行替换和删除,还有注释的删除,和文本操作,其中#define定义和头文件的包含都用到了预处理符号。

预处理符号

预定义符号

预定义符号是语言内置的符号,有以下几种:


__FILE__//进行编译的源文件__LINE__//文件当前的行号__DATE__//文件被编译的日期__TIME__//文件被编译的时间__STDC__//如果编译器遵循ANSI C,其值为1,否则未定义


#define

#define在前面学习常量的时候是有进行简略的介绍的,用#define定义的标识符常量,但是#define是不仅仅可以定义标识符常量的,还可以定义一些宏,那这些宏具体可以干什么呢?可以把他理解为另类的函数,宏的定义方法如下


#define name(parament-list) stuff;


其中name如何函数命一样,parament-list是一个符号表,可以理解为函数的参数,stuff可以理解为要实际做的事情,符号表内的符号会出现在stuff里面,对于宏来说,他实际是把name(parament-list)进行替换,替换成后面的是stuff,可以用代码进行验证一下:


#include<stdio.h>#define ADD(x,y) x+yintmain()
{
printf("%d", 3*ADD(3, 4));
return0;
}


image.png

表达式的结果式13,但是按照猜想得到的结果应该是21,3+4=7,在和3相乘,那13怎么得到的?上面说到,宏是进行的替换,将后面的3+4替换下来,那这个表达式实际上是3*3+4,就是9+4,那就是13,那可不可以让3+4先算在乘3呢?只需要加括号,对于宏来说,不要吝啬括号,那对上面代码进行修改:

#include<stdio.h>#define ADD(x,y) (x+y)intmain()
{
printf("%d", 3*ADD(3, 4));
return0;
}

image.png

那如果现在是一个乘法的宏呢?

#include<stdio.h>#define MUL(x,y) (x*y)intmain()
{
printf("%d", 3*MUL(3+3, 4+4));
return0;
}

image.png



和我们要得到的结果是不一样的,我们想要得到的是144,但是得到的是57,那我将内容替换到程序当中3+3*4+4,也就是3+12+4,得出19,19*3,得到57,但是我们想要的是先相加在相乘的,那就还需要加括号,如下所示:

#include<stdio.h>#define MUL(x,y) ((x)*(y))intmain()
{
printf("%d", 3*MUL(3+3, 4+4));
return0;
}

image.png

这样替换下来的就是(3+3)*(4+4),结果是48,和我们想要得到的结果是一样, 所以对于宏而言,不需要吝啬括号。

#define定义宏的替换步骤

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。

1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先

被替换。

2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值所替换。

3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上

述处理过程。


#和##的作用

在正常使用printf打印的时候可以将不用%s打印两个字符串吗?是可以的:

#include<stdio.h>intmain()
{
printf("这个数字是:""%d", 10);
return0;
}

image.png

那在宏中可以吗?也是可以的:

#include<stdio.h>#define PRINT(A ,B) printf("数字是"A"\n",B);intmain()
{
PRINT("%d",10);
return0;
}

image.png

但是这样只是对于字符串是参数的时候才能将字符串放进去,还有一种方法,就是利用#,它的作用是将一个宏参数变成字符串,如果现在要计算一个加法表达式的结果,就可以用这个来更直观的表达:


#include<stdio.h>#define PRINT(A ,B) printf(#B"的结果是"A"\n",B);intmain()
{
PRINT("%d",1+2);
return0;
}

image.png

##的作用

##可以把位于它两边的符号合成一个符号。

它允许宏定义从分离的文本片段创建标识符。

#include<stdio.h>#define _ADD(A ,B) num##A+=B;intmain()
{
intnum5=5;
_ADD(5, 10);
printf("%d", num5);
return0;
}

image.png

宏的副作用

对于宏来说,有些是有副作用的,比如++操作符,看下面的代码:>- 结果是什么?按照猜想的结果,a++是2,b++是3,然后比大小赋给c,3比2大,所以b++在执行一次,是4,那现在a是2,b是4,c也是4,结果是正确的吗?运行起来看看:

#include<stdio.h>#define MAX(A,B) ((A)>(B)?(A):(B))intmain()
{
inta=1;
intb=2;
intc=MAX(a++, b++);
printf("a= %d b= %d c=%d", a, b, c);
return0;
}

结果是什么?按照猜想的结果,a++是2,b++是3,然后比大小赋给c,3比2大,所以b++在执行一次,是4,那现在a是2,b是4,c也是4,结果是正确的吗?运行起来看看:

image.png

c是3,这就是因为,宏本质上还是替换,赋值给c的是((a++)>(b++)?(a++):(b++));这个表达式的结果是b++,而b++是先进行了一次++,得到3,表达式结果还是b++,但是是后置++,那就是先使用在++,那就是先赋值3,在进行++。

宏对比函数的优缺点

那宏和函数都可以实现某种功能,那他们有什么区别吗?就是单纯的书写格式不一样吗?不仅仅是这样,宏的优点在于宏的速度是优于函数的,并且对于宏,是不需要去定义类型的,那宏就没有缺点吗?有,当我们使用宏的时候,一份宏定义的代码将插入到程序中,除非宏比较短,否则可能大幅度增加程序的长度,而且宏是没法调试的,我们是不能直接进入宏调试的,因为宏是替换到程序当中,编译器是认得,但是我们是不知道内部有无问题的,而且上面说到宏没有定义类型,也就不够严谨,并且宏可能会带来运算符优先级的问题,导致我们想的和实际跑出来的内容不一样。

宏的命名

对于宏的命名而言,通常是全部大写的,这也是一个约定俗成的东西,而函数的命名就通常不是大写的,这也可以让其他程序员在看程序的时候,一眼看出来哪个是宏哪个是函数。

目录
打赏
0
0
0
0
2
分享
相关文章
Vue将Element Plus 进行自定义封装
Vue将Element Plus 进行自定义封装
278 0
内存回收
【10月更文挑战第9天】
251 5
Sora横空出世,AI视频时代崭露头角,我们准备好了吗?
2024年新春伊始,OpenAI新发布的Sora模型,在AI生成视频赛道扔下一枚深水炸弹,将曾经大火AI视频创业公司的模型直接碾压。
智慧医院系统,融合4级电子病历的云HIS系统,源码适合项目二开
智慧医院系统是一款融合4级电子病历的云HIS系统,采用云计算部署模式,支持无机房、无系统、无数据维护运行,大幅降低信息化成本。系统整合HIS与EMR功能,涵盖患者管理、电子病历、医嘱处理等核心业务,并支持与公卫、PACS等外部系统对接。其一体化电子病历设计提供丰富的模板、自动填充患者信息、结构化数据提取等功能,提升医生工作效率。同时,系统具备完善的审计日志、打印功能及病历质控管理,助力医疗机构实现高效、规范的信息化管理。
162 18
Nerdctl 原生支持 Nydus 加速镜像
OSPP 开源之夏是由中科院软件研究所“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动。旨在鼓励在校学生积极参与开源软件的开发维护、促进优秀开源软件社区的蓬勃发展、培养和发掘更多优秀的开发者。 这是去年(2022)的开源活动中,李楠同学参加 Nydus 容器开源生态集成课题的相关工作。
Nerdctl 原生支持 Nydus 加速镜像
【答疑】对象存储OSS常见问题解答(咨询类1)
1. OSS最大支持多大的文件? 解答:非multipart方式上传,最大支持5GB的文件; multipart方式上传,最大支持48.8TB。 通过控制台上传、简单上传、表单上传、追加上传的文件大小不能超过5GB, 要上传大小超过5GB的文件必须使用断点续传方式。
4487 0
阿里云云效操作报错合集之k8s直接返回401,该如何排查
本合集将整理呈现用户在使用过程中遇到的报错及其对应的解决办法,包括但不限于账户权限设置错误、项目配置不正确、代码提交冲突、构建任务执行失败、测试环境异常、需求流转阻塞等问题。阿里云云效是一站式企业级研发协同和DevOps平台,为企业提供从需求规划、开发、测试、发布到运维、运营的全流程端到端服务和工具支撑,致力于提升企业的研发效能和创新能力。
阿里云云效操作报错合集之k8s直接返回401,该如何排查

热门文章

最新文章

AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问