【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会被转化为 10
	return 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 + y

int 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 MAX
 
    int 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 HONG
 
int 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的用法不止以上三种,它还有其他的使用方法,这里就不一一介绍了,只介绍常用的相关用法。


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

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

防火墙第二次作业

一、什么是防火墙&#xff1f; 百度给出个一个定义&#xff1a;防火墙技术是通过有机结合各类用于安全管理与筛选的软件和硬件设备&#xff0c;帮助计算机网络于其内、外网之间构建一道相对隔绝的保护屏障&#xff0c;以保护用户资料与信息安全性的一种技术。 通俗的来讲&#…

由于找不到vcruntime140_1.dll,无法继续执行代码重新安装程序,怎么解决

vcruntime140_1.dll是Microsoft Visual C Redistributable for Visual Studio 2015中的一个动态链接库文件。它是用于支持在Windows操作系统上运行使用Visual C编写的应用程序或游戏所必需的文件之一。当出现vcruntime140_1.dll丢失的错误时&#xff0c;通常是由于缺少或损坏了…

《面试1v1》ElasticSearch架构设计

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

【前端】html

HTML标签&#xff08;上&#xff09; 目标&#xff1a; -能够说出标签的书写注意规范 -能够写出HTML骨架标签 -能够写出超链接标签 -能够写出图片标签并说出alt和title的区别 -能够说出相对路径的三种形式 目录&#xff1a; HTML语法规范HTML基本结构标签开发工具HTML常用标…

Stable Diffusion教程(8) - X/Y/Z 图表使用

1. 介绍 这项功能可以在 文生图/图生图 界面的左下角种 “脚本” 一栏内选择 “X/Y/Z 图表” 以启用。 它创建具有不同参数的图像网格。使用 X 类型和 Y 类型字段选择应由行和列共享的参数&#xff0c;并将这些参数以逗号分隔输入 X 值 / Y 值字段。支持整数、浮点数和范围。…

数据结构——单链表OJ题(第二弹)

单链表OJ题 前言一、返回链表开始入环的第一个节点思路一思路二 二、返回链表的深度拷贝总结 前言 此次练习题有两道&#xff01; 有点小难度&#xff0c;但相信难不住大家的&#xff01; 我也会给出两道OJ题的链接&#xff0c;大家也赶快去试一试吧 一、返回链表开始入环的第…

浅聊Cesium.js 后处理原理

浅聊Cesium.js 后处理原理 使用例子: const stages viewer.scene.postProcessStages;const silhouette Cesium.PostProcessStageLibrary.createSilhouetteStage() silhouette.enabled true; stages.add(silhouette);silhouette.uniforms.color Cesium.Color.LIME;涉及到相…

OSPF作业3

题目 地址配置 R1&#xff1a; R2&#xff1a; R3&#xff1a; R4&#xff1a; R5&#xff1a; R6&#xff1a; R7&#xff1a; R8&#xff1a; R9&#xff1a; R10&#xff1a; R11&#xff1a; R12&#xff1a; 私网通及LSDB优化 R1&#xff1a; ospf 1 router-id 1.1.1.1 …

关于Godot游戏引擎制作流水灯

先上核心代码 游戏节点 流水灯的通途可以是 1. 装饰 2. 音乐类多媒体程序&#xff08;如FL中TB-303的步进灯&#xff09; FL Studio Transistor Bass

STM32基础入门学习笔记:内部高级功能应用

文章目录&#xff1a; 一&#xff1a;低功耗模式 1.睡眠模式测试程序 NVIC.h NVIC.c key.h key.c main.c 2.停机模式测试程序 main.c 3.待机模式测试程序 main.c 二&#xff1a;看门狗 1.独立看门狗测试程序 iwdg.h iwdg.c main.c 2.窗口看门狗测试程序 wwdg…

深入理解缓存 TLB 原理

今天分享一篇TLB的好文章&#xff0c;希望大家夯实基本功&#xff0c;让我们一起深入理解计算机系统。 TLB 是 translation lookaside buffer 的简称。首先&#xff0c;我们知道 MMU 的作用是把虚拟地址转换成物理地址。 MMU工作原理 虚拟地址和物理地址的映射关系存储在页表…

Go语音介绍

Go语言介绍 Go 即Golang&#xff0c;是Google公司2009年11月正式对外公开的一门编程语言。 Go是静态强类型语言&#xff0c;是区别于解析型语言的编译型语言。 解析型语言——源代码是先翻译为中间代码&#xff0c;然后由解析器对代码进行解释执行。 编译型语言——源代码编…

20230807通过ffmpeg将DTS编码的AUDIO音频转换为AAC编码

20230807通过ffmpeg将DTS编码的AUDIO音频转换为AAC编码 2023/8/7 20:04 ffmpeg dts 转AAC 缘起&#xff1a;由于网上找的电影没有中文字幕&#xff0c;有内置的英文字幕&#xff0c;但是还是通过剪映/RP2023识别一份英文字幕备用&#xff01; I:\Downloads\2005[红眼航班]Red E…

【C++】Lambda表达式的使用

学习目标&#xff1a; 例如&#xff1a; 了解Lambda的优点 掌握Lambda表达式的使用 了解Lambda表达式的底层原理 学习内容&#xff1a; Lambda表达式的语法 文章目录 学习目标&#xff1a;学习内容&#xff1a;Lambda表达式排序案例Lambda表达式语法捕捉列表Lambda表达式模拟…

【Java设计模式】建造者模式 注解@Builder

概念 将一个复杂对象的构造与它的表示分离&#xff0c;使同样的构建过程可以创建不同的表示。它使将一个复杂的对象分解成多个简单的对象&#xff0c;然后一步步构建而成。 每一个具体建造者都相对独立&#xff0c;而与其它的具体建造者无关&#xff0c;因此可以很方便地替换具…

深度学习论文: RepViT: Revisiting Mobile CNN From ViT Perspective及其PyTorch实现

深度学习论文: RepViT: Revisiting Mobile CNN From ViT Perspective及其PyTorch实现 RepViT: Revisiting Mobile CNN From ViT Perspective PDF: https://arxiv.org/pdf/2307.09283.pdf PyTorch代码: https://github.com/shanglianlm0525/CvPytorch PyTorch代码: https://gith…

【并发专题】单例模式的线程安全(进阶理解篇)

目录 背景前置知识类加载运行全过程 单例模式的实现方式一、饿汉式基本介绍源码分析 二、懒汉式基本介绍源码分析改进 三、懒汉式单例终极解决方案&#xff08;静态内部类&#xff09;&#xff08;推荐使用方案&#xff09;基本介绍源码分析 感谢 背景 最近学习了JVM之后&…

Permute 3 for mac音视频格式转换

Permute是一款Mac平台上的媒体格式转换软件&#xff0c;由Chaotic Software开发。它可以帮助用户快速地将各种音频、视频和图像文件转换成所需格式&#xff0c;并提供了一些常用工具以便于用户进行编辑和处理。 Permute的主要特点包括&#xff1a; - 支持大量格式&#xff1a;支…

2020年09月 Python(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题 第1题 Python自带的编程环境是&#xff1f; A&#xff1a;PyScripter B&#xff1a;Spyder C&#xff1a;Notepad D&#xff1a;IDLE 正确的答案是&#xff1a;D Python自带的编程环境是IDLE&#xff08;Integrated Development and Learning Environment&a…

【c语言初级】c++基础

文章目录 1. C关键字2. 命名空间2.1 命名空间定义2.2 命名空间使用 3. C输入&输出4. 缺省参数4.1 缺省参数概念4.2 缺省参数分类 5. 函数重载5.2 C函数重载的原理--名字修饰采用C语言编译器编译后结果 1. C关键字 C是在C的基础之上&#xff0c;容纳进去了面向对象编程思想…