【C语言】预处理(下)(C语言完结篇)

一、#和##

1、#运算符

这里的#是一个运算符,整个运算符会将宏的参数转换为字符串字面量,它仅可以出现在带参数的宏的替换列表中,我们可以将其理解为字符串化。

我们先看下面的一段代码:

第二个printf中是由两个字符串组成的,这样写法的输出和第一个写法输出是否会有不同呢?

运行结果:
 

可以看到,这两个挨在一块的字符串会被合并起来输出。 

下面我们通过一个例子来弄清楚# 符号到底是怎么个事:

我们现在想在屏幕上打印the value of a is 20 。那么我们可以如下面一样操作:

但是当我们需要对其他几个变量也打印这样的信息呢?那么是不是要重复的写这么一长串的代码,有没有什么办法可以将其简化?

此时我们可以通过宏来解决这个问题,在上面的字符串中,不同的变量发生变化的有三个地方:

一个就是of后面的,这个地方是要填入的是变量名,然后是占位符,然后就是参数了。

参数是比较好解决的,主要是变量名和占位符,这是因为这两个都是字符串,所以我们在使用宏替换的时候,是不会将其替换的,此时是不是就没办法了呢?

对于占位符的替换,我们可以用上面那个代码的情况,两个字符串是可以合并的。

还有就是对于变量名,其就需要使用到我们的#运算符了,我们上面提到了其可以将我们后面的内容字符串化。

代码如下:

 ​​​​

我们看看其运行结果:

可以看到其完美的实现了我们需要的功能。 


2、##运算符

##运算符又是一个完全陌生的符号,其作用是将其两边的符号合成一个符号,其运算宏定义从分离的文本片段创建标识符。##被称为记号粘合运算符。

比如我们现在有一个变量class115,那么我们可以通过粘合class和115来得到它

如下:

我们将其合并后,那么其此时就可以表示我们的变量了,那么我们使用printf将其打印出来,看看是不是10。

如下:

可以看到其可以顺利得到我们的这个变量名字。

下面我们再通过一个例子理解这个运算符:

我们前面使用函数写过一个比较两个数的大小,当我们比较的两个数是整数的时候,那我们就需要写一个整型数据求最大值的函数,当要求浮点数的时候,就需要写一个浮点数使用的函数,但是我们可以知道的是,这两个函数除了返回值类型,和参数的数据类型不一样罢了,其他的都是一样的。

如下:

下面我们通过宏来定义:

这个宏要实现的功能就是根据我们传入的数据类型,然后生成对应的求最大值的函数。

那么主要是解决对于数据类型如何与函数名相连了,那么刚刚好可以使用##进行粘合。

这些函数的名字的共同点如:数据类型_max。

如下:

上面就是我们创建的对于不同的数据类型都可以使用的求最大值的宏,我们根据用户传入的type来确定函数的名字和函数的返回值类型,然后\是一个换行符号。

这里我们使用了##运算符将type与_max连接起来,可以让用户传入的type可以完美的替换。

那么我们就可以通过这个宏来创建需要使用到的求最大值的函数:

运行结果:

二、预处理指令#under 

#under指令的作用是移除一个#define的定义,其语法如下:

其中NAME就是我们要移除的#define定义的名字了,当我们需要使用这个名字重新定义一个宏的时候,那么我们就需要使用#under将其原来的定义移除,然后才可以使用这个名字进行定义一个新的宏。

如下:

上面我们首先使用#define将N定义为100,然后将其在屏幕上打印,然后我们使用#undef先将其原来的定义移除,然后再将N重新定义为hehe字符串,然后将其在屏幕上打印。

 

三、条件编译 

条件编译,类似于我们的选择语句,不过这个过程是在预处理阶段进行的,它会根据我们的条件来决定是否对某些语句进行编译。

1、单分支条件翻译

单分支条件编译就是说我们只有一条分支需要进行判断。

其语法如下:

 可以发现其和if语句类似,也是有个条件表达式决定其里面的内容编译不编译,不过其比if语句多了一个结束的标志。

不过条件表达式其要求的是常量表达式,下面我们使用其看看效果:

那么这个代码就啥都不会打印。因为常量表达式的值是为假的。

那么为什么后面只能为常量表达式呢?这是因为在这个阶段是预处理阶段,在这个阶段,变量还不存在,那么也就不能使用变量了,只能使用常量

2、多分支条件编译 

多分支编译和单分支编译的原理大致相同,不过其就是多了几个选择这样。

其语法如下:

这个就是我们的多分支条件编译的语法,其用法和if -else的差不多,就是在第一个#if要是不满足,那么就看#elif的条件是否满足,要是满足则运行其代码,要是不满足,要是这两个都不满足,那么就会运行#else的内容,然后就结束。

如下:
 

上面的代码其是满足#elif的条件,那么我们看看其是否可以将hehe打印在屏幕上。

运行结果:

 

下面我们试试当前面两个的都不满足,其是否会运行#else的内容:

 

运行结果:

 可以看到确实是如此。

那么细心的同学就会发现了,在我们的多分支条件编译中,会被编译的代码会比不被进行编译的代码颜色更深。

3、判断符号是否被定义

在编译一个程序的时候,如果我们要将一条语句,编译或者放弃编译,那么我们可以使用条件编译,比如调试性的代码,我们在调试完后,将其删去又会很浪费,但是保留又会很难看,影响我们代码的可读性,那么我们就可以使用条件编译,在编译的时候不编译这些调试性代码。

例如我们在开头使用了#define定义一个符号,如果我们没有注释或者删除这个符号,那么我们是可以编译里面的调试性代码的,反之就不可以编译。但是这个是不会影响代码的正常运行的。

我们先学习如何进行判断一个符号是否被定义:

1、使用#if  define进行判断其语法如下:

2、使用#ifdef进行判断:

     

使用#ifdef的话,要判断的符号就不需要使用括号了。

下面我们使用其判读符号是否被定义:

我们首先定义一个GEBUG的符号,然后在main函数中创建一个变量a,然后我们使用#ifdef判断这个GEBUG符号是否被定义,要是被定义了就将这个变量打印出来。

如下:

 

运行结果:

 

我们注释掉它的定义后,那么就不会打印这个变量了:

 

4、判断符号是否没有被定义 

其和上面的判断符号是否被定义差不多:

1、使用#if !defined:这个就是我们上面使用到的#if defined的前面加上一个非符号。

2、使用#ifndef:这个就是在上面的#ifdef加上一个n,表示no实际上就是表示否定。

四、头文件的包含

头文件的包含我们一直都有在使用,其本质上是拷贝,当我们包含一个头文件后,会直接将头文件的内容拷贝过来,下面我们具体学习一下头文件的包含。

1、库头文件的包含

库头文件里面包含了C语言的库函数和一些其他功能,我们只需要包含库的头文件就可以直接使用。

我们包含头文件的语法就是:

#include<头文件>

2、本地头文件的包含

本地头文件就是我们自己写的头文件,这种我们自己实现的头文件的话,我们包含其的语法如下:

#include "头文件"

3、如何避免重复包含头文件

我们在包含头文件中,我们可能会造成嵌套的包含,也就是可能会多次包含同一个头文件,那么这就会造成代码的冗余。

那么我们有没有什么办法解决这个问题呢?

我们可以使用条件编译指令:

就是使用#ifndef或者使用#if  !defined这两个指令。

因为头文件其是就是简单的拷贝,那么我们可以在头文件中的开头写下面的代码:

或者使用预处理指令#pragma

这种方法比上面的还简答,我们可以在当前程序下创建一个头文件,我们可以发现头文件中自动包含了一条语句。

 

这样也可以达到我们想要的效果。

五、C语言完结 

感想各位大佬们的阅读、点赞、收藏和评论,后面我们就会对数据结构的学习。

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

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

相关文章

【高性能缓存Redis_中间件】一、快速上手redis缓存中间件

一、铺垫 在当今的软件开发领域&#xff0c;消息队列扮演着至关重要的角色。它能够帮助我们实现系统的异步处理、流量削峰以及系统解耦等功能&#xff0c;从而提升系统的性能和可维护性。Redis 作为一款高性能的键值对数据库&#xff0c;不仅提供了丰富的数据结构&#xff0c;…

Java如何获取文件的编码格式?

Java获取文件的编码格式 在计算机中&#xff0c;文件编码是指将文件内容转换成二进制形式以便存储和传输的过程。常见的文件编码格式包括UTF-8、GBK等。不同的编码使用不同的字符集和字节序列&#xff0c;因此在读取文件时需要正确地确定文件的编码格式 Java提供了多种方式以获…

客户端负载均衡与服务器端负载均衡详解

客户端负载均衡与服务器端负载均衡详解 1. 客户端负载均衡&#xff08;Client-Side Load Balancing&#xff09; 核心概念 定义&#xff1a;负载均衡逻辑在客户端实现&#xff0c;客户端主动选择目标服务实例。典型场景&#xff1a;微服务内部调用&#xff08;如Spring Cloud…

Quartus II的IP核调用及仿真测试

目录 第一章 什么是IP核&#xff1f;第二章 什么是LPM&#xff1f;第一节 设置LPM_COUNTER模块参数第二节 仿真 第三章 什么是PLL&#xff1f;第一节 设置ALTPLL&#xff08;嵌入式锁相环&#xff09;模块参数第二节 仿真 第四章 什么是RAM&#xff1f;第一节 RAM_1PORT的调用第…

各地物价和生活成本 东欧篇

东欧地区的物价差异相对较大&#xff0c;一些国家的物价较高&#xff0c;而另一些国家则相对便宜。这些差异主要受当地经济发展水平、工资水平、旅游业发展以及国际关系等因素影响。以下是一些典型的东欧国家&#xff0c;按物价高低进行分类&#xff1a; &#x1f30d; 物价较高…

改进神经风格迁移

改进神经风格迁移&#xff08;Neural Style Transfer, NST&#xff09;可以从多个方向入手&#xff0c;包括模型结构优化、损失函数设计、计算效率提升、应用场景扩展等。以下是一些关键的改进方向及具体方法&#xff1a; 1. 模型结构优化 &#xff08;1&#xff09;轻量化网络…

1、从零搭建魔法工坊:React 19 新手村生存指南

一、开篇&#xff1a;新世界的入场券 "你好&#xff0c;年轻的魔法学徒&#xff01;欢迎来到React魔法世界。我是你的向导赫敏韦斯莱&#xff0c;今天我们将用React 19这根全新魔杖&#xff0c;搭建属于你的第一座魔法工坊。" ——以对话形式开场&#xff0c;消除技…

基于 Redis 实现一套动态配置中心 DCC 服务与反射基础知识讲解

目录 动态配置中心核心价值 轻量级 Redis 方案与 ZooKeeper 的对比分析 为什么选择自定义 Redis 方案&#xff1f; 1. 技术决策背景 一、活动降级拦截 1. 定义与作用 2. 实现原理 二、活动切量拦截 1. 定义与作用 2. 实现原理 三、两者的核心区别 四、实际应用案例 1. 电商大促…

如何从项目目标到成功标准:构建可量化、可落地的项目评估体系

引言 在项目管理领域&#xff0c;"项目成功"的定义往往比表面看起来更复杂。根据PMI的行业报告&#xff0c;67%的项目失败源于目标与成功标准的不匹配。当项目团队仅关注"按时交付"或"预算达标"时&#xff0c;常会忽视真正的价值创造。本文将通…

深度学习基础--CNN经典网络之分组卷积与ResNext网络实验探究(pytorch复现)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 前言 ResNext是分组卷积的开始之作&#xff0c;这里本文将学习ResNext网络&#xff1b;本文复现了ResNext50神经网络&#xff0c;并用其进行了猴痘病分类实验…

SQL 全文检索原理

全文检索(Full-Text Search)是SQL中用于高效搜索文本数据的技术&#xff0c;与传统的LIKE操作或简单字符串比较相比&#xff0c;它能提供更强大、更灵活的文本搜索能力。 基本概念 全文检索的核心思想是将文本内容分解为可索引的单元(通常是词或词组)&#xff0c;然后建立倒排…

【Linux】Orin NX编译 linux 内核及内核模块

1、下载交叉编译工具:gcc 1)下载地址:https://developer.nvidia.com/embedded/jetson-linux 选择TOOLS中的交叉编译工具:gcc 11.3 2)解压 将gcc编译器解压到指定目录中,如:/home/laoer/nvidia/gcc 3)配置环境变量 创建: ~/nvidia/gcc/env.sh添加: #!/bin/bash e…

Transformers 是工具箱,BERT 是工具。

Transformers 是工具箱&#xff0c;BERT 是工具。 &#x1f50d; 详细解释&#xff1a; 名称作用比喻理解举例&#x1f916; transformers&#xff08;库&#xff09;一个框架&#xff0c;提供很多 NLP 模型的“使用方式”&#xff0c;包括文本分类、问答、摘要等相当于一个“…

k8s之Service类型详解

1.ClusterIP 类型 2.NodePort 类型 3.LoadBalancer 类型 4.ExternalName 类型 类型为 ExternalName 的 Service 将 Service 映射到 DNS 名称&#xff0c;而不是典型的选择算符&#xff0c; 例如 my-service 或者 cassandra。你可以使用 spec.externalName 参数指定这些服务…

find指令中使用正则表达式

linux查找命令能结合正则表达式吗 find命令要使用正则表达式需要结合-regex参数 另&#xff0c;-type参数可以指定查找类型(f为文件&#xff0c;d为文件夹) rootlocalhost:~/regular_expression# ls -alh 总计 8.0K drwxr-xr-x. 5 root root 66 4月 8日 16:26 . dr-xr-…

《穿透表象,洞察分布式软总线“无形”之奥秘》

分布式系统已成为众多领域的关键支撑技术&#xff0c;而分布式软总线作为实现设备高效互联的核心技术&#xff0c;正逐渐走入大众视野。它常被描述为一条“无形”的总线&#xff0c;这一独特属性不仅是理解其技术内涵的关键&#xff0c;更是把握其在未来智能世界中重要作用的切…

Ubuntu虚拟机连不上网

桥接 虚拟机Ubuntu系统必须能连接到外网&#xff0c;不然不能更新软件安装包 配置虚拟机网络&#xff08;关机或者挂起状态&#xff09; 第一步1.重启虚拟机网络编辑器&#xff08;还原配置&#xff09; 第二步2.重启虚拟机网络适配器&#xff08;移除再添加&#xff09; 启…

rom定制系列------红米9A批量线刷原生安卓14双版 miui系统解锁可登陆线刷固件

红米9A。联发科Helio G25芯片。该处理器支持64位运算‌&#xff0c;但此机miui系统运行环境是32位的&#xff0c;这意味着尽管处理器本身支持64位计算&#xff0c;但miui系统限制在32位环境下运行‌。官方miui系统稳定版最终为12.5.21安卓11的版本。 原生安卓14批量线刷功能固…

Matlab 分数阶PID控制永磁同步电机

1、内容简介 Matlab 203-分数阶PID控制永磁同步电机 可以交流、咨询、答疑 2、内容说明 略 3、仿真分析 略 4、参考论文 略

Flink的 RecordWriter 数据通道 详解

本文从基础原理到代码层面逐步解释 Flink 的RecordWriter 数据通道&#xff0c;尽量让初学者也能理解。 1. 什么是 RecordWriter&#xff1f; 通俗理解 RecordWriter 是 Flink 中负责将数据从一个任务&#xff08;Task&#xff09;发送到下游任务的组件。想象一下&#xff0c;…