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

news2024/11/25 1:00:55

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


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

 

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

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

相关文章

运动耳机哪个最好、顶级运动耳机推荐

拥有一款出色的运动耳机&#xff0c;是每个运动爱好者追求完美体验的必备选择。今天&#xff0c;我为大家推荐五款顶级运动耳机&#xff0c;它们不仅将音乐和运动完美结合&#xff0c;还具备出色的防水性能、舒适的佩戴感和激动人心的音质表现&#xff0c;让你在运动中尽情释放…

人到中年不得已,保温杯里泡枸杞--送程序员

目录 一&#xff1a;你现在身体的体能状况如何&#xff1f;你有身体焦虑吗&#xff1f; 二&#xff1a;如何保持规律性运动&#xff1f; 三&#xff1a;你有哪些健康生活的好习惯&#xff1f; 大厂裁员&#xff0c;称35岁以后体能下滑&#xff0c;无法继续高效率地完成工作&…

阿里云官方关于数据安全保护的声明

“阿里云监控用户的数据流量&#xff1f;”“真的假的&#xff1f;”随着近日早晨 朱峰肥鹅旅行 对阿里云的一条朋友圈截图传遍了整个IT圈。 对于网络上的各种传播&#xff0c;以下是阿里云的官方答复&#xff0c;原文如下&#xff1a; 关于数据安全保护的声明 今天有客户反映…

Django实现音乐网站 ⑺

使用Python Django框架制作一个音乐网站&#xff0c; 本篇主要是后台对歌手原有实现功能的基础上进行优化处理。 目录 新增编辑 表字段名称修改 隐藏单曲、专辑数 姓名首字母 安装xpinyin 获取姓名首字母 重写保存方法 列表显示 图片显示处理 引入函数 路径改为显示…

P1156 垃圾陷阱(背包变形)

垃圾陷阱 题目描述 卡门――农夫约翰极其珍视的一条 Holsteins 奶牛――已经落了到 “垃圾井” 中。“垃圾井” 是农夫们扔垃圾的地方&#xff0c;它的深度为 D D D&#xff08; 2 ≤ D ≤ 100 2 \le D \le 100 2≤D≤100&#xff09;英尺。 卡门想把垃圾堆起来&#xff0c…

星辰天合成功入选“2023 中国大数据企业 50 强”

8 月 3 日&#xff0c;大数据与数字经济大会暨 2023&#xff08;第八届&#xff09;大数据产业生态大会在京圆满举办。论坛期间&#xff0c;隆重揭晓了 2023 中国数据英雄、2023 中国大数据企业 50 强等奖项&#xff0c;星辰天合凭借在数据基础设施领域的领先技术优势&#xff…

Java的抽象类不能被实例化

Java的抽象类不能被实例化。如果试图实例化&#xff0c;会编译报错。 示例&#xff1a; 定义一个抽象类&#xff1a; package com.thb;public abstract class AbstractPoint {public AbstractPoint() {} }再定义一个主类&#xff1a; package com.thb;public class Test4 {p…

人工智能普及之JAVA AI 课程第一课

JAVA & AI 课程第一课 未来已来&#xff0c;2023注定最火的是AI,大家也许听说过AI,AIGC、GPT。那么这些专业名词都是什么意思&#xff1f;又将对我们未来的生活产生什么影响呢&#xff1f; 一.概念篇(扫盲) AI 人工智能&#xff08;Artificial Intelligence&#xff09;&…

Maven: No compiler is provided in this environment.

在Eclipse中运行Maven项目&#xff0c;报错&#xff1a; No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 解决方法&#xff1a; Windows > Preferences > Java > Installed JREs > Add > Standard VM,…

vue-virtual-scroller的使用,展示巨量数据,长列表优化,虚拟列表

一、原理 计算显示区域的高度&#xff08;或宽度&#xff09; 和显示区域的起始位置&#xff08;scrollTop或scrollLeft&#xff09;根据每个元素的尺寸和总数目&#xff0c;计算出整个列表的高度&#xff08;或宽度&#xff09;显示区域的高度&#xff08;或宽度&#xff09…

netty面试题2

1、一次完整的HTTP请求的所经历的步骤 1、首先进行DNS域名解析&#xff08;本地浏览器缓存、操作系统缓存或者DNS服务器&#xff09;&#xff0c;首先会搜索浏览器自身的DNS缓存&#xff08;缓存时间比较短&#xff0c;大概只有1分钟&#xff0c;且只能容纳1000条缓存&#xff…

STM32单片机蓝牙APP宠物自动喂食器定时语音提醒喂食系统设计

实践制作DIY- GC00162---蓝牙APP宠物自动喂食器 一、功能说明&#xff1a; 基于STM32单片机设计---蓝牙APP宠物自动喂食器 二、功能说明&#xff1a; STM32F103C系列最小系统板LCD1602显示器DS1302时钟模块5个按键语音播报模块ULN2003步进电机模块LED灯板HC-05蓝牙模块&#x…

了解Linux 的 mmap --- 笔记

学习这篇博客&#xff0c;进行了一些归纳Linux下mmap_linux mmap_一个山里的少年的博客-CSDN博客https://blog.csdn.net/qq_56999918/article/details/127070280 >>读取文件 读取文件方法&#xff1a;由操作系统提供的两个方法&#xff0c;read和write来读写文件。 由…

eNSP:mgre与ospf的优化综合实验

实验要求&#xff1a; 第一步&#xff1a;路由器、IP的配置 r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int g 0/0/0 [r1-GigabitEthernet0/0/0]ip add 172.16.1.1 20 [r1-GigabitEthernet0/0/0]int lo0 [r1-LoopBack0]ip a…

C#,数值计算——堆选择(Heap Select)的计算方法与源程序

1 简述 HeapSelect 是一种用于选择数组中第 K 个最大元素的算法。它是选择问题的变体&#xff0c;涉及在无序或偏序集合中查找特定元素。 算法概要&#xff1a;数组被转换为最大堆&#xff0c;然后反复删除根节点并替换为下一个最大的元素&#xff0c;直到找到第 K 个最大的元…

2023《财富》500强|500强中超过10%已是盖雅客户,100强中已合作超过1/4

7月11日 &#xff0c;财富中文网发布了 &#xff0c;该榜单覆盖范围包括在中国境内外上市的所有中国公司&#xff0c;根据全球范围内最大的中国上市企业过去一年的业绩和成就进行排名。因此&#xff0c;上榜的上市公司不仅是经营规模大&#xff0c;绝大多数也是各自行业的龙头…

【LeetCode】240.搜索二维矩阵Ⅱ

题目 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,…

【无标题】云原生在工业互联网的落地及好处!

什么是工业互联网&#xff1f; 工业互联网&#xff08;Industrial Internet&#xff09;是新一代信息通信技术与工业经济深度融合的新型基础设施、应用模式和工业生态&#xff0c;通过对人、机、物、系统等的全面连接&#xff0c;构建起覆盖全产业链、全价值链的全新制造和服务…

软件测试工程师的基础必备技能:功能测试解读

什么是功能测试&#xff1f; 根据百科的官方定义&#xff1a;功能测试就是对产品的各功能进行验证&#xff0c;根据功能 测试用例&#xff0c;逐项测试&#xff0c;检查产品是否达到用户要求的功能。 通俗的解读&#xff1a; 功能测试&#xff0c;也叫行为测试&#xff0c;即测…

【mysql】实现递归查询

mysql实现递归查询的方法&#xff1a;首先创建表&#xff0c;并初始化数据&#xff1b;然后向下递归&#xff0c;利用find_in_set()函数和group_concat()函数、with recursive实现递归查询。 mysql实现递归查询的方法&#xff1a; 1、创建表 DROP TABLE IF EXISTS t_areainf…