详解预处理(2)

news2024/11/19 14:35:56

目录

#undef

命令行定义

条件编译

NO1.

NO2.多个分支的条件编译

NO3.判断是否被定义

NO4.嵌套指令

文件包含

头文件被包含的方式

本地文件包含

库文件包含

 嵌套文件包含

其他预处理指令


今天接着继续讲解预处理的点,前面已经深入学习了#define。

#undef

#undef 这条指令用于移除一个宏定义。

#undef NAME
如果现存的一个名字需要被重新定义,那么它的旧名字首先要被移除。

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

 

命令行定义

命令行定义是什么呢?

许多C 的编译器提供一种能力,允许在命令行中定义符号。用于启动编译预处理阶段过程

命令行是在命令行中给一些符号指定值。

例如:当我们根据同一个源文件要编译出不同的一个程序的不同版本的时候,这个特性有点用处。(假定某个程序中声明了一个某个长度的数组,如果机器内存有限,我们需要一个很小的数组,但是另外一个机器内存大写,我们需要一个数组能够大写。)

下面到gcc编译器上验证一下。

#include<stdio.h>
int main()
{
	int arr[SZ];
	int i = 0;
	for (i = 0; i < SZ; i++)
	{
		arr[i] = i;
	}
	for (i = 0; i < SZ; i++)
	{
		printf("%d ", arr[i]);
	}
	return 0;
}

 

  • 变长数组是指数组大小由变量指定,在程序运行的时候指定变量的大小
  • 命令行定义是指程序在编译阶段指定变量的大小

条件编译

在编译一个程序的时候我们如果要将一条语句(一组语句)编译或者放弃是很方便的。因为我们有条件编译指令。

条件编译是指满足条件就编译,不满足条件就不编译。

哪些地方会用到条件编译呢?

比如 :调试性的代码,删除可惜,保留又碍事,所以我们可以选择性的编译。还有当我们写的代码有跨平台的使用,一个文件有windows底下使用的代码,又含有Linx底下使用的代码。准对不同的平台,编译环境的不同,我们需要选择性的编译代码。

接下来,我们介绍一下常见的条件编译。

NO1.

常量表达式为真 的时候参与编译,为假 的时候不参与编译,#if 和 #endif 是配套的。

1.
#if 常量表达式
//...
#endif
//常量表达式由预处理器求值。
#include<stdio.h>
int main()
{
#if 1
	printf("hehe\n");
#endif
	return 0;
}

 

NO2.多个分支的条件编译

  • 常量表达式为真 的时候参与编译,为假 的时候不参与编译。
  • 只选择一个表达式为真的执行。
  • 如果有多个表达式为真,选择首先出现表达式为真的编译执行。
2.多个分支的条件编译
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
#include<stdio.h>
int main()
{
#if 0
	printf("hehe\n");
#elif 2==1
	printf("haha\n");
#elif 3==1
	prntf("heihei\n");
#elif 1
	printf("xixi\n");
#endif
	return 0;
}

如果多个表达式为真呢?

#include<stdio.h>
int main()
{
#if 0
	printf("hehe\n");
#elif 1==1
	printf("haha\n");
#elif 3==1
	prntf("heihei\n");
#elif 1
	printf("xixi\n");
#endif
	return 0;
}

 

NO3.判断是否被定义

  • defined(symbol) 成立编译执行 ;不成立不编译执行
  • !defined(symbol) 成立编译执行 ;不成立不编译执行
  • 两种写法都要掌握
3.判断是否被定义

#if defined(symbol)//第一种写法
#ifdef symbol//第二种写法
//反之
#if !defined(symbol)
#ifndef symbol
//两种写法一样的效果
#include<stdio.h>
#define M 0
int main()
{
#if defined(M)//不是看M的真假而是看M是否被定义过没有
	printf("hehe\n");
#endif

#ifdef M//两种写法都可以
	printf("hehe\n");
#endif
	return 0;
	return 0;
}

同理 !defined 

NO4.嵌套指令

#if defined(OS_UNIX)
       #ifdef OPTION1
              unix_version_option1();
       #endif
       #ifdef OPTION2
              unix_version_option2();
       #endif
       #elif defined(OS_MSDOS)
       #ifdef OPTION2
              msdos_version_option2();
       #endif
       #endif

在我们的头文件#include<stdio.h>,有很多这样的嵌套指令的使用,大家自己下去看一看。关于嵌套指令,在当前我们学习进度下,就是头文件的包含。我们来介绍一下。

文件包含

我们已经知道, #include 指令可以使另外一个文件被编译。就像它实际出现于 #include 指令的地方一样。

这种替换的方式很简单: 预处理器先删除这条指令,并用包含文件的内容替换。 这样一个源文件被包含10次,那就实际被编译10次。

头文件被包含的方式

本地文件包含

#include"test.h"

查找策略:

  • 先在源文件所在目录下查找,如果该头文件未找到
  • 编译器就像查找库函数头文件一样在标准位置查找头文件。
  • 如果找不到就提示编译错误。

Linux环境的标准头文件的路径:

VS环境的标准头文件的路径:(不确定--建议自己按照自己安装的路径去查找)

库文件包含

#include<test.h>
  • 查找头文件直接去标准路径下去查找,如果找不到就提示编译错误。

综上所诉: 这样是不是可以说,对于库文件也可以使用" "的形式包含? 答案是肯定的,可以。
但是这样做查找的效率就低些,当然这样也不容易区分是库文件还是本地文件了

头文件的包含有两种形式:

  • 包含本地文件(自己.h文件)   #include"xxx.h"
  • 包含标准库的头文件  #include<xxx.h>   #include"xxx.h" 

 嵌套文件包含

在大型工程项目中出现下面这种情况,该怎么办?

 comm.h和comm.c是公共模块。 test1.h和test1.c使用了公共模块。 test2.h和test2.c使用了公共模块。 test.h和test.c使用了test1模块和test2模块。 这样最终程序中就会出现两份comm.h的内容。这样就造成了文件内容的重复。

解决办法:条件编译

每个头文件的开头写:

#ifndef __TEST_H__
//定义了的话将不在定义,未定义的话编译执行下面代码
#define __TEST_H__//头文件的内容
//定义
...
....
#endif //__TEST_H__

或者写这个:

#pragma once

就可以避免头文件重复引入的问题了。

注:推荐《高质量C/C++编程指南》里面有这样两道笔试题:

1. 头文件中的 ifndef/define/endif是干什么用的?
2. #include <filename.h> 和 #include "filename.h"有什么区别?

学完上面的知识,相信你心中一定有了答案了。 

其他预处理指令

#error
#pragma
#line
...
#pragma pack()在结构体部分介绍。

后前会更新一个专栏去学习《C语言深度解剖》 这本书。大家要乖乖敲代码哦。

✔✔✔✔✔最后感谢大家的阅读,若有错误和不足,欢迎指正!

代码---------→【gitee:唐棣棣 (TSQXG) - Gitee.com】

联系---------→【邮箱:2784139418@qq.com】

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

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

相关文章

基于Springboot 游戏娱乐信息平台-计算机毕设 附源码 04691

Springboot 游戏娱乐信息平台 目 录 摘要 1 绪论 1.1研究内容 1.2国内外研究慨况 1.3研究方法 1.4论文结构与章节安排 2 游戏娱乐信息平台系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 法律可行性分析 2.2 系统功能分析 2.2.1 功能性…

EvilAppleJuice(邪恶苹果汁)-ESP32C3项目(iphone疯狂弹窗)

原作者作品页&#xff1a; ckcr4lyf/EvilAppleJuice-ESP32: Spam Apple Proximity Messages via an ESP32 (github.com) 代码优化一下&#xff0c;增加呼吸灯效果方便知道设备运行情况&#xff0c;我是用arduino烧录 仅作交流学习使用&#xff0c;请勿在公开场合滥用 运行效果…

黑豹程序员-Python入门-for循环

文章目录 1、for循环语法2、巩固案例&#xff1a;长安三万里你记得的三位诗人&#xff1f;实现步骤&#xff1a;第一步&#xff1a;新建一个列表&#xff0c;存储诗人姓名第二步&#xff1a;列表用[]表示&#xff0c;元素之间用逗号,分隔第三步&#xff1a;用列表[索引]的方法将…

莫名其妙el-table不显示问题

完全复制element-ui中table代码&#xff0c;发现表格仍然不显示&#xff0c;看别人都说让降低版本&#xff0c;可我不想降低啊&#xff0c;不然其他组件有可能用不了&#xff0c;后来发现可以通过配置vite.config.js alias: {: path.resolve(__dirname, src),vue: vue/dist/vue…

【Docker】Python Flask + Redis 练习

一、构建flask镜像 1.准备文件 创建app.py,内容如下 from flask import Flask from redis import Redis app Flask(__name__) redis Redis(hostos.environ.get(REDIS_HOST,127.0.0.1),port6379)app.route(/) def hello():redis.incr(hits)return f"Hello Container W…

nexus5x 刷机root

刷机 进入fastboot模式 adb reboot bootloader 或者开机 音量减 解锁bootloader fastboot oem unlock 刷入rom包 下载 Nexus 和 Pixel 设备的出厂映像 | Google Play services | Google for Developers 选一个合适的ROM包下载到电脑的某个位置&#xff0c;然后unzip解…

国家网信办发布第十三批境内区块链信息服务备案编号

2019年2月15日《区块链信息服务管理规定》&#xff08;以下简称《管理规定》&#xff09;正式实施以来&#xff0c;国家互联网信息办公室依法依规组织开展备案审核工作&#xff0c;已发布2批次共506个境内区块链信息服务名称及备案编号&#xff0c;近日正式发布第三批共224个境…

剪映怎么合并两个视频?几个步骤轻松搞定!

合并两个视频可以方便我们管理、节省存储空间、提高处理效率、满足特定要求或实现特定效果等目的。而剪映作为我们常用的视频处理软件&#xff0c;如何利用其合并两个视频呢&#xff1f;一起来看看吧&#xff5e; 方法一&#xff1a;使用剪映专业版 1、运行剪映&#xff0c;主…

关于maven项目中依赖无法下载的解决方案

场景描述 在下载selenium的依赖时&#xff0c;虽然相依的jar包已经存在&#xff0c;但是在idea中依然报红 解决方案 在jar无法正常下载时可以尝试使用——找到下载的文件夹&#xff0c;删除整个文件夹后重新通过链接下载 过程演示 C:\Users\lenovo\.m2 所有依赖的jar包都在这…

errno变量和显示错误信息

一、errno Linux很多函数发生错误&#xff0c;只会返回-1。所以&#xff0c;我们只知道函数发生了错误&#xff0c;却不知道具体发生了什么错误。 因此Linux 系统下对常见的错误做了一个编号&#xff0c;每一个编号都代表着每一种不同的错误类型。 发生错误时&#xff0c;对…

CTF-Crypto学习记录-第三天 MD5加密算法(信息摘要算法)“ “

文章目录 0x1 MD5 基本介绍0x2 MD5 加密特点0x3 MD5 加密原理步骤0x01 对明文数据进行信息填充0x02 设置初始变量0x03 加密运算过程加密运算流程图&#xff1a;四个非线性函数&#xff1a;Mj表示消息的第j个子分组&#xff08;从0到15&#xff09;&#xff0c;<<&#xf…

Python web开发中的单元测试自动化技巧!

Python作为一种广泛使用的编程语言&#xff0c;在web开发中也扮演着重要的角色。在进行web开发时&#xff0c;单元测试是一个不可或缺的环节。单元测试可以确保代码的正确性&#xff0c;并且能够在开发过程中快速发现问题&#xff0c;有助于提高代码质量和开发效率。 在Python…

非计算机小白成功转型Python教学分析师,月薪2W后,我的学习经验总结!

最近1年的主要学习时间&#xff0c;都投资到了python据分析和数据挖掘上面来了&#xff0c;虽然经验并不是十分丰富&#xff0c;但希望也能把自己的经验分享下&#xff0c;最近也好多朋友给我留言&#xff0c;和我聊天&#xff0c;问我python该如何学习&#xff0c;才能少走弯路…

桉木红面模板批发915*1830mm规格建筑木胶板

我们很自豪地介绍我们的产品&#xff1a;桉木红面建筑模板。作为一家专业的建筑木胶板生产批发商&#xff0c;我们提供高质量的915*1830*15mm规格的桉木红面板&#xff0c;为您的建筑项目提供卓越的解决方案。 桉木红面板是由优质的桉木原料制成&#xff0c;经过精细的加工和处…

论文分享——北邮:基于学习解纠缠因果子结构的图神经网络去偏

作者 &#xff1a;范少华 研究方向 &#xff1a;图神经网络 论文标题 &#xff1a;基于学习解纠缠因果子结构的图神经网络去偏 论文链接 &#xff1a;https://arxiv.org/pdf/2209.14107.pdf        https://doi.org/10.48550/arXiv.2209.14107 大多数图神经网络(GNNs)通…

基于YOLOv8模型的烟雾目标检测系统(PyTorch+Pyside6+YOLOv8模型)

摘要&#xff1a;基于YOLOv8模型的烟雾目标检测系统可用于日常生活中检测与定位烟雾目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的目标检测&#xff0c;另外本系统还支持图片、视频等格式的结果可视化与结果导出。本系统采用YOLOv8目标检测算法训练数据集…

【面试题】面试官:如何判断两个数组的内容是否相等

给大家推荐一个实用面试题库 1、前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;web前端面试题库 题目 给定两个数组&#xff0c;判断两数组内容是否相等。 不使用排序不考虑元素位置 例&#xff1a; [1, 2, 3]…

【软件测试】了解JUnit单元测试框架常用注解

目录 1、认识JUnit 2、Junit中常见的注解 1、Test 2、Disabled 3、BeforeAll和AfterAll 4、BeforeEach和AfterEach 5、 ParameterizedTest&#xff1a;参数化 6、order 3、断言 1、断言相等【Assertions.assertEquals(预期&#xff0c;比较值)】&#xff1b;相等测试通…

RabbitMQ (4)

RabbitMQ (4) 文章目录 1. 死信的概念2. 死信的来源3. 死信代码案例3.1 TTL 过期时间3.2 超过队列最大长度3.3 拒绝消息 前言   上文我们已经学习完 交换机 &#xff0c;知道了几个交换机的使用 &#xff0c;下面我们来学习一下 死信队列 1. 死信的概念 先从概念解释上搞清楚这…

契约锁助力电子检测报告应用,杜绝假证书、出证更便捷

国家市场监管总局发布的最新数据显示&#xff1a;2022年&#xff0c;全国5.2万家检验检测机构出具检验检测报告共6.5亿份。按照一份纸质报告3-5页、成本约15元计算&#xff0c;“电子检测报告”的应用可以帮助检验检测行业一年节省约27亿张纸、97.5亿元的成本费。 引入电子签章…