【C语言学习——————预处理3000字讲解】

欢迎阅读新一期的c语言学习模块————预处理

✒️个人主页:-_Joker_-

🏷️专栏:C语言

📜代码仓库:c_code

🌹🌹欢迎大佬们的阅读和三连关注,顺着评论回访🌹🌹


文章目录

  • 什么是预处理
  • 宏定义#define
  • #undef
  • #include 
  • 条件编译
  • #error
  • #pragma


什么是预处理

预编译又称为预处理 , 是做些代码文本的替换工作。
处理以# 开头的指令 , 比如拷贝 #include 包含的文件代码,#define 宏定义的替换 , 条件编译等,就是为编译做的预备工作的阶段。

主要处理#开始的预编译指令,预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。

C 编译系统在对程序进行通常的编译之前,首先进行预处理。

c 提供的预处理功能主要有以下三种:

1 )宏定义 
2 )文件包含 
3 )条件编译

何时需要预编译:

总是使用不经常改动的大型代码体。
程序由多个模块组成,所有模块都使用一组标准的包含文件和相同的编译选项。在这种情况下,可以将所有包含文件预编译为一个“预编译头”

在c语言中有如下预处理指令

 下面介绍几个常用的预处理指令

一. 宏定义(#define)

常用的宏定义有以下几种:

①宏常量

我们最常使用到的#define的用法就是用#define来定义一个符号常量,而要修改时,只需修改#define这条语句就行了,不必每处代码都修改

例如

#include"stdio.h"
#define A 10
int main()
{printf("A = %d" , A);//在预处理时,A会被转化为 10return 0;
}

在预处理时,A会被转变为10

结果如下

 ②宏语句

宏定义除了可以定义一些常量之外,我们还可以用来定义一些语句

例如

#include <stdio.h>#define Print(str) printf("%s", str)int main()
{Print("这是一个宏定义的输出语句");//在程序预处理时会变为printf("%s", str);return 0;
}

在预处理时,Print会被转变为printf("%s", str);

结果如下

③宏函数

宏除了可以定义常量和语句以外,也可以用来定义一些函数

例如

#include <stdio.h>#define ADD(x, y) x + yint main()
{printf("%d", ADD(10, 20));return 0;
}

在预处理时,编译器会将10和20带入宏定义的ADD(x, y) ,并且将ADD(x, y)转变为 x + y,所以原语句 <==>printf("%d", 10 + 20);

结果如下

宏定义不止可以定义常量,语句,函数,它还可以用来实现递归调用等,宏定义类似于函数,但是又和函数不同,宏定义在预处理时需要编译器进行预处理,每一次对宏定义的函数/语句/常量的引用都需要进行一次转化。在定义结构较简单,使用次数较少的函数时,宏定义的预处理时间可以忽略不计,宏定义的效率会比函数要更高,但是如果多次调用宏定义函数的话,系统会不断对宏定义的语句进行处理,从而消耗很多时间,这种情况下的效率是要低于函数的,所以宏定义和函数是各有春秋,可以根据使用需求的不同来使用不同的方法。

二、#undef

这个预处理命令也就是undefine的意思,即撤销宏定义。也就是说宏定义的生命周期从#define开始到#undef结束。

在实际应用中可以按照以下方式使用

1. 防止宏定义冲突

在一个程序块中用完宏定义后,为防止后面标识符冲突需要取消其宏定义。


#include <stdio.h>int main()
{
#define MAX 200
printf("MAX = %d\n", MAX);
#undef MAXint MAX = 10;printf("MAX = %d\n", MAX);return 0;}
在一个程序段中使用完宏定义后立即将其取消,防止在后面程序段中用到同样的名字而产生冲突。

2. 增强代码可读性

在同一个头文件中定义结构类型相似的对象,根据宏定义不同获取不同的对象,主要用于增强代码的可读性。


#include <stdio.h>#define MING
#include "student.h"
#undef MING
#define HONG
#include "student.h"
#undef HONGint main()
{
printf("Xiao Ming's age is %d.\n", MING_AGE);
printf("Xiao Hong's age is %d.\n", HONG_AGE);return 0;
}
在一个头文件里定义的两个对象与分别在两个头文件里定义效果相同,但如果将相似的对象只用一个头文件申明,可以增强源代码的可读性。

三、#include

这是我们最常见的词语了。在编译一个程序的时候,首先第一句话就是#include <stdio.h>啦。它同样也非常重要,是将多个源文件连接成一个源文件进行编译,结果就生成一个目标文件(obj)。常见有两种形式:

1.include <xxx.h>

用尖括号括起来的头文件一般都是系统自带的,表示系统将在指定的路径进行寻找。

2.include "xxx.h"

双引号一般则用于我们自己编写的头文件,系统也会优先在当前目录中查找。如果找不到指定文件名的文件就会和形式1一样在指定的路径进行寻找。

四、条件编译

平常写代码过程中,我们为了实现分支结构会经常使用if else结构,在预处理同样也有类似的功能,即条件编译。我们可以按照不同的条件去编译不同的部分,这对程序的移植和调试有着巨大的帮助。条件编译主要有以下两种形式。

1.#ifdef 标识符1  &&  #ifndef 标识符2

//code1

#else

//code2

#endif

这一段就是经典的条件编译。如果定义了标识符1(或如果没有定义(ifndef)标识符2),执行代码段code1;否则执行code2.

要注意的是#ifdef或#ifndef需要和#endif对应。

2.#if 常量表达式

//code1

#else

//code2

#endif

这段则无限接近我们日常使用的if else了。同样要注意endif。

除此之外还有一个#elif,即是elseif,形成if else_if 阶梯状语句,可以进行多种编译选择。

 五、#error

#error的作用是用于提示报错信息,当程序运行到#error时会生成一个错译信息,这个错误信息是由系统已经定义好了的,它会根据错误类型生成一个提示并停止程序。这里就不作过多介绍,如果想要了解可以通过链接进行了解--->#error 指令 (C/C++)

六、#pragma

#pragma是以上预处理指令中较为复杂的一个,同时也是功能较为强大的一个,它的用法如下:

1.#pragma once

这是一个比较常用于自定义的函数头文件中的预处理指令,通常在头文件的最开始处加上这句话,就可以避免头文件的重复引用(include)。它的作用就是保证每个头文件只编译一次,再加入同名的头文件也没有关系(反正也不编译,且不会报错)。

2.#pragma warning

此指令用于和warning有关的操作(即非致命编程错误的警告)。

具体示例:

#pragma warning (disable:4707)     //屏蔽4707警告

#pragma warning (once:4706)         //只显示一次4706警告

#pragma warning (error:164)           //将164号警告当作一个错误。

也可以三合一写成:#pragma warning (disable:4707;once:4706;e
编译器将 4000 添加到 0 和 999 之间的任何警告编号。

具体用法及详细使用方法可以参照警告 pragma

3.#pragma pack

这个预处理指令设计到了内存对齐相关的问题,它的作用是设定最小对齐数,它可以用来更改结构体的对齐方式,如果不清楚内存对齐的小伙伴可以参考【C语言学习——————————结构体对齐案例解析】

如果对这条预处理指令的用法及注意事项有兴趣的小伙伴,可以参考pack pragma

#pragma的用法不止以上三种,它还有其他的使用方法,这里就不一一介绍了,只介绍常用的相关用法。


 以上带来的就是预处理的相关介绍。

 

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

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

相关文章

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)--功能实现[五]

文章目录 SSM--功能实现实现功能09-带条件查询分页显示列表需求分析/图解思路分析代码实现测试分页条件查询带条件分页查询显示效果 实现功能10-添加家居表单前端校验需求分析/图解思路分析代码实现完成测试测试页面效果 实现功能11-添加家居表单后端校验需求分析/图解思路分析…

Spring接口InitializingBean的作用和使用介绍

在Spring框架中&#xff0c;InitializingBean接口是一个回调接口&#xff0c;用于在Spring容器实例化Bean并设置Bean的属性之后&#xff0c;执行一些自定义的初始化逻辑。实现InitializingBean接口的Bean可以在初始化阶段进行一些必要的操作&#xff0c;比如数据的初始化、资源…

2023巅峰极客比赛web复现

<1> unserialize(反序列化字符串逃逸) 下载 www.zip得到源码&#xff1a; my.php 存在 pull_it恶意类 反序列化时会执行 $this-x 这里有一层过滤 $this-x不能为字母数字 可以取反、异或绕过 下面来找一找怎么去触发反序列化 index.php 会对我们登录框输入的参数先…

Markdown系列之Flowchat流程图

一.欢迎来到我的酒馆 介绍Markdown的Flowchart流程图语法。 目录 一.欢迎来到我的酒馆二.什么是Flowchart三.更进一步 二.什么是Flowchart 2.1 Flowchart是一款基于javascript的工具&#xff0c;使用它可以用代码创建简单的流程图。具体信息可以查看flowchart官网&#xff1a;…

【暑期每日一练】 Epilogue

目录 选择题&#xff08;1&#xff09;解析&#xff1a; &#xff08;2&#xff09;解析&#xff1a; &#xff08;3&#xff09;解析&#xff1a; &#xff08;4&#xff09;解析&#xff1a; &#xff08;5&#xff09;解析&#xff1a; 编程题题一描述输入描述&#xff1a;输…

ad+硬件每日学习十个知识点(23)23.8.3(LDO 设计实例)(涉及到自控没听懂,学完自控再回来看)

文章目录 1.输入电容的选取&#xff08;两个&#xff0c;一个大电容&#xff0c;一个小电容&#xff09;2.输出电容的选取&#xff08;两个&#xff0c;一个大电容&#xff0c;一个小电容&#xff09;3.有些LDO需要输出的最小负载电流&#xff0c;所以需要接一个下拉电阻。4. 1…

电影售票后台管理系统快速搭建(优惠券制作+java开源)

为了快速搭建电影售票后台管理系统并实现优惠券制作功能&#xff0c;你可以按照以下步骤进行操作&#xff1a; 1. 确定系统的需求和功能&#xff0c;包括用户管理、影院管理、电影管理、订单管理以及优惠券制作等模块。 2. 选择一款适合的Java开源框架来搭建系统&#xff0c;…

【Megatron-DeepSpeed】张量并行工具代码mpu详解(三):张量并行层的实现及测试

相关博客 【Megatron-DeepSpeed】张量并行工具代码mpu详解(三)&#xff1a;张量并行层的实现及测试 【Megatron-DeepSpeed】张量并行工具代码mpu详解(一)&#xff1a;并行环境初始化 【Megatron-DeepSpeed】张量并行工具代码mpu详解(二)&#xff1a;Collective通信操作的封装ma…

SOME/IP学习笔记1

SOA概念 在SOA中,每个服务就好像我们每一个人在社会中扮演的角色,在对别人提供着服务的同时,同时也享受着别人提供出来的服务,人与人之间,既是彼此独立的,又是需要互相通讯的。服务提供者将功能具象为一组接口,这样使用者就能知道如何调用服务,完成某件事情,得到某个…

Windows下调试UEFI程序:Visual Studio调试

以edk2\MdeModulePkg\Application\HelloWorld这个项目作为调试目标。 1. 使用VS2017建立Makefile工程 VS2017, 新建 project&#xff0c;取名X64dbg_vs。 Visual C > Other > Makefile Project, 注意项目路径为HelloWord程序路径。 随便填写config中的字符串&#xff…

【并发编程】ShenyuAdmin里面数据同步用到的无锁环形队列LMAX Disruptor并发框架

并发&#xff0c;数据同步往往是业务开发中比较重要的部分。 shenyu网关数据同步设计方案图 shenyu官网给出的同步设计方案图如下&#xff1a; 基于事件异步并发框架com.lmax.disruptor 下载下示例代码&#xff0c;跑起来发现&#xff0c;在shenyuAdmin模块里面用到了com.lma…

【2.2】Java微服务:nacos的使用

✅作者简介&#xff1a;大家好&#xff0c;我是 Meteors., 向往着更加简洁高效的代码写法与编程方式&#xff0c;持续分享Java技术内容。 &#x1f34e;个人主页&#xff1a;Meteors.的博客 &#x1f49e;当前专栏&#xff1a; 深度学习 ✨特色专栏&#xff1a; 知识分享 &…

观测数据建模

观测数据 观测数据 / 样本空间覆盖均匀 psm 观测数据建模 因果模型得到什么样的值 base 0/1 gmv uplift delat 模型可以得到 confounder 的表征&#xff0c;而 NN 可以支持更个性化的结构。在这里给出两种思路&#xff1a; 思路1: 使用树模型生成的 confounder embedd…

React diff 根据相对位置的 diff 算法

文章目录 diff 算法没有 key 时的diff通过 key 的 diff查找需要移动的节点移动节点添加新元素移除不存在的元素缺点 diff 算法 没有 key 时的diff 根据新旧列表的长度进行 diff 公共长度相同的部分直接patch新列表长度>旧列表长度则添加&#xff0c;否则删除 function pa…

Vue3_02 创建Vue3.0工程

1.使用 vue-cli 创建 ## 查看 vue/cli 版本&#xff0c;确保 vue/cli 版本在4.5.0以上 vue -V 或 vue --version## 安装或升级你的 vue/cli npm install -g vue/cli## 创建 vue create vue_test## 启动 cd vue-test npm run serve 2.使用 vite 创建 什么是vite?——新一代…

图像 检测 - DETR: End-to-End Object Detection with Transformers (arXiv 2020)

图像 检测 - DETR: End-to-End Object Detection with Transformers - 端到端目标检测的Transformers&#xff08;arXiv 2020&#xff09; 摘要1. 引言2. 相关工作2.1 集预测2.2 Transformers和并行解码2.3 目标检测 3. DETR模型References 声明&#xff1a;此翻译仅为个人学习…

深度学习,计算机视觉任务

目录 计算机视觉任务 1.K近邻算法 2.得分函数 3.损失函数的作用 4.向前传播整体流程 5.反向传播计算方法 计算机视觉任务 机器学习的流程&#xff1a; 数据获取 特征工程 建立模型 评估与应用 计算机视觉&#xff1a; 图像表示&#xff1a;计算机眼中的图像&#…

万界星空科技/免费开源MES系统/免费仓库管理

仓库管理&#xff08;仓储管理&#xff09;&#xff0c;指对仓库及仓库内部的物资进行收发、结存等有效控制和管理&#xff0c;确保仓储货物的完好无损&#xff0c;保证生产经营活动的正常进行&#xff0c;在此基础上对货物进行分类记录&#xff0c;通过报表分析展示仓库状态、…

开源项目如何贡献代码

以腾讯犀牛鸟开源项目ncnn为例 目录 fork项目仓库 添加远程仓库 同步更新仓库 贡献代码提交新PR PR未merge更新PR fork项目仓库 只需要做一次 到仓库页面点击fork&#xff0c;然后create forkTencent/ncnn: ncnn is a high-performance neural network inference frame…

性能测试浅谈

早期的性能测试更关注后端服务的处理能力。 一个用户去访问一个页面的请求过程&#xff0c;如上图。 数据传输时间 当你从浏览器输入网址&#xff0c;敲下回车&#xff0c;开始... 真实的用户场景请不要忽视数据传输时间&#xff0c;想想你给远方的朋友写信&#xff0c;信件…