【C语言进阶】还说不会?一文带你全面掌握计算机预处理操作

news2024/11/28 13:34:45

目录

🍊前言🍊:

🍈一、宏与函数🍈:

        1.宏与函数对比:

        2.宏与函数的命名约定:

🍓二、预处理操作符🍓:

        1.预处理操作符 " # ":

        2.预处理操作符 " ## ":

🥝三、条件编译🥝:

        1.简述条件编译指令:

        2.常见条件编译指令:

🍒总结🍒:


🛰️博客主页:✈️銮同学的干货分享基地

🛰️欢迎关注:👍点赞🙌收藏✍️留言

🛰️系列专栏:💐【进阶】C语言学习

                       🧧  C语言学习

🛰️代码仓库:🎉VS2022_C语言仓库

        家人们更新不易,你们的👍点赞👍和⭐关注⭐真的对我真重要,各位路过的友友麻烦多多点赞关注,欢迎你们的私信提问,感谢你们的转发!

        关注我,关注我,关注我,你们将会看到更多的优质内容!!


🏡🏡 本文重点 🏡🏡:

🚅 宏与函数 🚃 预处理操作符 🚃 条件编译🚏🚏

🍊前言🍊:

        在上节课中,我们对程序编译的环境、编译链接过程以及很重要的预处理指令 #define 进行了研究,对于程序的预处理过程有了一定的了解,而这节课我们将要继续学习预处理的一些相关知识,帮助我们更加全面的掌握程序的预处理过程。

🍈一、宏与函数🍈:

        1.宏与函数对比:

        我们之前在使用宏 #define 时,常用于定义一些全局的宏常量等。而现在我们要知道的是,宏还常常被应用于执行简单的运算,例如比较两数的大小我们可以这样用:

#define MAX(a,b) ((a)>(b)?(a):(b))

#include<stdio.h>
int main()
{
	int a = 5;
	int b = 10;
	printf("MAX = %d\n", MAX(a, b));
	return 0;
}

        那么可能有的小伙伴就会问了,那为什么我们不使用函数来完成这个过程呢

★ 在这里使用宏而不用函数的主要原因有两个:

①. 相比于函数宏在程序规模与速度方面更胜一筹:由于函数在调用时牵扯到函数栈帧的创建与销毁等操作,所以用于调用函数以及从函数返回的耗时可能比实际执行这个小型计算工作的耗时更多

②. 宏是类型无关的:更重要的是我们都知道,在声明、定义和使用函数时,函数的参数必须是特定的类型,所以函数只能在类型合适的特定表达式上使用。反观宏,无论是整形、长整型还是浮点型,都可以进行比较

        但是我们说宏也有缺点

★ 当然宏与函数相比也有劣势:

①. 宏只能处理简单运算:我们知道在预处理阶段宏将会进行符号替换,这就意味着每次在使用宏的时候,一份宏定义的代码将插入到程序中。这样一来,如果宏比较长,就将会大幅度增加程序代码的长度

②. 宏是没有办法进行调试的

③. 由于宏具有类型无关的特点,因此也不够严谨

④. 宏可能会带来运算符优先级的问题,导致程序容易出错。

        可是,宏也可以做到函数做不到的事。比如在宏中可以出现类型,而函数不可以

#define MALLOC(num,type) (type*)malloc(num*sizeof(type))

#include<stdio.h>
#include<string.h>
int main()
{
	MALLOC(10, int);
	//预处理器替换后:(int*)malloc(10 * sizeof(int));
	return 0;
}

        2.宏与函数的命名约定:

        一般来讲,我们使用的宏定义函数,与普通函数的使用语法很相似,这就导致语言本身无法帮我们区分二者。所以我们通常对二者的命名进行约定

①. 宏的名称全部大写。

②. 函数名不要全部大写。

        如此就可以帮助我们区分二者,提升我们程序代码的可读性了。

🍓二、预处理操作符🍓:

        首先我们来看这样的一段代码:

int main()
{
	char* p = "Hellow ""world\n";
    //*p指向两个常量字符串
	printf("Hellow world\n");
	printf("%s", p);

	return 0;
}

        当我们将其编译运行发现,打印结果均为字符串“ Hellow world”

        于是由此我们就可以得知,字符串具有自动连接的特点。那么我们是不是就可以写出下面这样的代码呢?

#define PRINT(FORMAT,VALUE) printf("The value of VALUE is "FORMAT"\n",VALUE);
//可以使用宏来定义函数
//字符串"The value of VALUE is "与"\n"将会自动连接
//构造函数等价于printf("the value of VALUE is %d\n",VALUE);

#include<stdio.h>
int main()
{
	int a = 10;
	PRINT("%d", a + 3);

	return 0;
}

        在这段代码中,我们使用了宏来构造一个新的函数,在这个我们自己构造出来的宏函数中,其中的两个短字符串将会自动连接成为一整个长字符串,并根据我们输入的参数进行打印。于是在这个过程中,就衍生出了两个实用的预处理操作符:# 与 ##

        1.预处理操作符 " # ":

        预处理操作符" # "的作用:将宏参数转变成其对应的字符串

        这是什么意思呢?例如下面这段代码中所使用的 #N

#define _CRT_SECURE_NO_WARNINGS 1
#define PRINT(N) printf("The value of "#N" is %d\n",N);
#N将被视为字符串"N",且字符串 N 在打印时打印的是字符串 N 的内容

#include<stdio.h>
int main()
{
	int a = 10;
	PRINT(a + 3);

	return 0;
}

         在这段代码中,#N 将会被处理为字符串 N ,即" a + 3 ",于是整个宏定义函数就相当于:

printf("The value of ""a + 3"" is %d\n",VALUE);

        即相当于字符串"The value of "字符串"a + 3"字符串" is %d\n"之间进行了自动连接,成为了一整个长字符串

        则最终的输出结果为:

        2.预处理操作符 " ## ":

        预处理操作符" ## "的作用:将位于其两边的符号合成为一个符号

        并且,它允许宏定义从分离的文本片段中创建标识符

        

#define CAT(CLASS,NAME) CLASS##NAME
//宏定义函数的作用为将符号 CLASS 与符号 NAME 合并为符号 CCLASSNAME

#include<stdio.h>
int main()
{
	int class3xiaohong = 888;
	int back = CAT(class3, xiaohong);
	//使用宏定义函数 CAT ,将符号 class3 与符号 xiaohong 合并为 class3xiaohong
	//而符号 class3xiaohong 表示的是值为 888 的 int 类型变量,故用 int 类型变量 back 接收并打印或执行其他操作
	printf("%d\n", back);

	return 0;
}

        在这段代码中,通过宏定义的预处理操作符" ## "将符号" class3 "与符号" xiaohong "进行了合并,合并成了符号" class3xiaohong ",接着我们看到,在这之前我们就已经定义并初始化了 int 类型变量 class3xiaohong,于是我们就可以使用 int 类型的变量对宏定义函数所合成的符号" class3xiaohong "所表示的值进行接收了。

        最后进行打印,验证符号合成结果:

🥝三、条件编译🥝:

        1.简述条件编译指令:

        通过使用条件编译指令,我们在编译一段代码时如果要将一条(或一组)语句编译或舍弃是很方便的。例如一些调试性的代码,删除可惜,保留碍事,于是我们就可以通过使用条件编译指令来实现选择性的进行编译。 

        例如

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
		printf("%02d ", arr[i]);
#if 0
		printf("\n");
#endif
	}

	return 0;
}

        在这段代码中,包含在条件编译指令 #if 与 #endif 之间的换行打印是否执行,就取决于条件编译指令的参数,此时参数为 0 ,即为假,则不进行换行打印

        那么我们再将参数改为1,即真

#include<stdio.h>

int main()
{
	int arr[10] = { 0 };
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		arr[i] = i + 1;
		printf("%02d ", arr[i]);
#if 1
		printf("\n");
#endif
	}

	return 0;
}

        这时条件编译指令参数为真,于是执行其中的代码进行换行打印:

        2.常见条件编译指令:

        ①. 单分支条件编译指令:

#if 常量表达式
    //执行操作
#endif

//或:常量表达式由预编译器求值:
#define __DEBUG__ 1

#if __DEBUG__
    //执行操作
#endif

        ②. 多分枝条件编译指令:

#if 常量表达式
    //执行操作
#elif 常量表达式
    //执行操作
#elif 常量表达式
    //执行操作
...

#endif

        ③. 判断是否被定义:

#if defined(symbol)
    //如果 symbol 被定义过,则执行操作
#endif

//或:
#if !defined(symbol)
    //如果 symbol 没有被定义过,则执行操作
#endif

        ④.嵌套指令:

#if defined(MAX)
    #if 1
        printf("%d\n", a > b ? a : b);
    #endif
#elif define(MIN)
    #if 0
        printf("%d\n", a < b ? a : b);
    #endif
#endif

        通过灵活的嵌套使用条件编译指令,就能实现某条或某组程序代码的选择性编译

🍒总结🍒:

        到这里,我们关于预处理部分的讲解就全部结束了。但是各位小伙伴们可不能就此放松,基础知识的讲解并不意味着我们学习的终结。C 语言是高深而奇妙的,语言学习的道路永无尽头,希望各位小伙伴们能够静下心来多多深入研究,不断发掘C语言的深层逻辑,提升个人的编程能力。同时我们关于 C 语言的进阶之路也就到此为止了。至此我们的 C 语言语法已经全部讲解完毕了,再往后就将进入我们的数据结构与算法部分的学习之中了,各位小伙伴们,期待那时与你们的再次相会,我们随后再会!

        🔥🔥只有承担起旅途风雨,最终才能守得住彩虹满天🔥🔥

        更新不易,辛苦各位小伙伴们动动小手,👍三连走一走💕💕 ~ ~ ~  你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正!

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

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

相关文章

C语言学生成绩管理系统

程序示例精选 C语言学生成绩管理系统 如需安装运行环境或远程调试&#xff0c;见文章底部微信名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<C语言学生成绩管理系统>>编写代码&#xff0c;代码整洁&#xff0c;规则&#xff0c;易读。 …

DFS算法-leetcode java题解

DFS算法-leetcode java题解 本文目录DFS算法-leetcode java题解leetcode 547. 省份数量leetcode 463. 岛屿的周长leetcode 200. 岛屿数量leetcode 130. 被围绕的区域leetcode 417. 太平洋大西洋水流问题leetcode 17. 电话号码的字母组合leetcode 22. 括号生成leetcode 39. 组合…

List 容器的接口使用、迭代器失效(仅erase)

目录 一、接口使用 ① 构造函数 ②迭代器 ③ 容量与元素修改 ④ remove ⑤remove_if ⑥ unique ⑦sort&#xff08;&#xff09; ⑧ merge() 二、对于迭代器失效问题 一、接口使用 ① 构造函数 void MyListTest1() {list<int> l1;list<int> l5(10, 5);vector…

〖产品思维训练白宝书 - 产品思维认知篇⑦〗- 聊一聊 产品经理 的工作内容与职责划分

大家好&#xff0c;我是 哈士奇 &#xff0c;一位工作了十年的"技术混子"&#xff0c; 致力于为开发者赋能的UP主, 目前正在运营着 TFS_CLUB社区。 &#x1f4ac; 人生格言&#xff1a;优于别人,并不高贵,真正的高贵应该是优于过去的自己。&#x1f4ac; &#x1f4e…

自定义类型【c语言】

前言&#xff1a; c语言提供了丰富的内置类型&#xff0c;但是在描述一些复杂对象的时候仍不能满足一定的功能&#xff0c;因此c语言为了支持我们能描述一些复杂对象给出了我们能自定义的一些类型&#xff0c;因此便有了自定义类型。 在之前我们已经初步对结构体进行相应的了解…

提升工作效率,领导都夸的开源数据可视化工具

echarts官网有很多好看的图例&#xff0c;怎么结合起来放到自己的项目中呢&#xff1f;比如这种酷酷的首页&#xff1a; 这种看起来美观又大方&#xff0c;自己要是能用上就好了。 其实这是可以的&#xff0c;echarts上有现成的图例和示例代码&#xff0c;咱们只要改改数据源就…

华为防火接与二层交换机对接配置VLAN上网设置

拓扑图 一、防火墙设置 1、G1/0/0接口设置IP&#xff0c;G1/0/1接口切换二层口设置VLAN&#xff0c;G1/0/0 桥接了本地无线网卡来模拟外网地址 <USG6000V1>sys [USG6000V1]sys FW1 [FW1]un in en# 设置外网IP [FW1]int g1/0/0 [FW1-GigabitEthernet1/0/0]ip addr 192.1…

ORB-SLAM2 --- LocalMapping::SearchInNeighbors函数

0.函数更新内容 仅对地图点进行融合。 1.函数作用 检查并融合当前关键帧与相邻帧&#xff08;两级相邻&#xff09;重复的地图点。 2.函数步骤 Step 1&#xff1a;获得当前关键帧在共视图中权重排名前nn的邻接关键帧 Step 2&#xff1a;存储一级相邻关键帧及其二级相邻关键帧 将…

Java变量的作用域:静态变量、全局变量和局部变量

变量的作用域规定了变量所能使用的范围&#xff0c;只有在作用域范围内变量才能被使用。根据变量声明地点的不同&#xff0c;变量的作用域也不同。根据作用域的不同&#xff0c;一般将变量分为不同的类型&#xff1a;成员变量和局部变量。下面对这几种变量进行详细说明。成员变…

代码随想录训练营第四十二天

1.背包问题 1.1 01背包 有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]&#xff0c;得到的价值是value[i] 。每件物品只能用一次&#xff0c;求解将哪些物品装入背包里物品价值总和最大。 1.1.1 用动态规划的方法解决------二维dp数组01背包 ①确定dp…

学一下这个60秒的男人

程序员求职简历&#xff0c;项目经验怎么写&#xff1f;免费修改简历、提供模板并内部推荐今天想跟大家聊一下这个“60秒”的男人。10月21日&#xff0c;罗辑思维发文&#xff1a;《罗胖60秒&#xff1a;10年期满&#xff0c;今日告别》。10年前&#xff0c;罗振宇开始干一件事…

智能防雷,智能防雷系统的应用研究方案

“智慧智能防雷”是近年来防雷界提出的一个全新的防雷理念&#xff0c;是防雷业发展的趋势。所谓“智慧智能防雷”&#xff0c;是将大数据分析、云存储、人工智能、移动互联网和物联网技术融入到传统防雷措施中&#xff0c;并通过软、硬件系统的集成&#xff0c;实现对特定的区…

企业微信收款后可以进行退款吗?如何操作?

很多企业使用企业微信运营&#xff0c;就是看中了企业微信对外收款的功能&#xff0c;它不仅简化了转账步骤&#xff0c;而且可以在必要时直接完成退款&#xff0c;操作简单方便。前言随着企业微信的普及度&#xff0c;越来越多的企业认识到企业微信运营功能的强大&#xff0c;…

带你了解2023新版本Internet Download Manager有哪些新功能优势

作为一款体积只有10M的下载软件&#xff0c;IDM却常年霸占着各软件评测榜的前列。它的界面简洁清爽&#xff0c;使用过程中无弹窗、无广告&#xff0c;小小的体积竟能将下载速度提升5倍&#xff01;该软件一进入中国市场&#xff0c;便受到了广大用户的追捧&#xff0c;被大家亲…

2023年留学基金委(CSC)联合培养博士研究生项目解读及建议

近日&#xff0c;国家留学基金委&#xff08;CSC&#xff09;公布了2023年国家建设高水平大学公派研究生项目&#xff0c;该项目分为两部分&#xff0c;1.申请攻读博士学位研究生&#xff1b;2.申请联合培养博士研究生。本文知识人网小编仅就联合培养博士研究生部分进行解读&am…

【生信】R语言进行id转换的方法(附可直接使用代码)

本文我都默认已经下载好了表达矩阵exp了哦 代码都是直接给出来了&#xff0c;需要修改的地方我进行了标记 一般只要修改一下都能直接用了 方法一&#xff1a;下载平台数据以得到对应信息 然后进入官网https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi&#xff0c;在这里我以G…

【数据结构】4.4 数组

4.4.1 数组的定义 数组&#xff1a; 按照一定格式排列起来的&#xff0c;具有相同类型的数据元素的集合。 一维数组&#xff1a; 若线性表中的数据元素为非结构的简单元素&#xff0c;则称为一维数组。逻辑结构&#xff1a;线性结构&#xff0c;固定长度的线性表。声明格式…

如何学习微服务架构?(项目学习)

哪些项目适合使用微服务架构&#xff1f;对于一般的公司来说&#xff0c;微服务的实践有着很大的技术挑战&#xff0c;所以并不是所有的公司都适合将整体架构拆分成微服务架构。一般来说&#xff0c;微服务架构更适合于未来具有一定扩展复杂度、具有大量增量用户期望的应用&…

最新综述:基于语言模型提示学习的推理

©PaperWeekly 原创 作者 | OE-Heart引言推理能力是人类智能的核心能力之一。随着预训练技术的不断发展&#xff0c;大模型辅之以提示学习&#xff08;如 Chain-of-Thought Prompting [1]&#xff09;涌现出一系列的惊人的推理能力&#xff0c;引起了学术界、工业界学者的…

动态规划——数位dp

数位dp 文章目录数位dp概述题目特征基本原理计数技巧模板例题度的数量思路代码数字游戏思路代码不要62思路代码概述 数位是指把一个数字按照个、十、百、千等等一位一位地拆开&#xff0c;关注它每一位上的数字。如果拆的是十进制数&#xff0c;那么每一位数字都是 0~9&#xf…