预处理详解(二)-- 条件编译 - 头文件包含 - ##和#运算符

news2024/11/27 2:33:16

目录

  • 一.##和#运算符
    • 1.#运算符(字符串化)
    • 2.##运算符(粘合符)
  • 二.条件编译(很重要)
  • 三.命名约定
    • 1.宏名的命名
    • 2.函数的命名
  • 四.#undef(用于移除一个宏定义)
  • 五.命名行约定
  • 六.头文件被包含的方式
    • 1.本地文件包含
    • 2.库文件包含
    • 3.嵌套文件包含(重复引入了同一个头文件)

在这里插入图片描述

一.##和#运算符

1.#运算符(字符串化)

#运算符将宏的参数变成一个字符串 这里的#并不是#include或#define中的# 在举例子之前,说明一下字符串是有自动连接的特点的

printf("hello""world");
//打印后是helloworld

在这里插入图片描述

#define PRINT(n) printf("the value of" #n "is %d",n); 
int a = 10;
printf("the value of"#a"is""%d",a);
//      the value of a is 10

在这里插入图片描述

2.##运算符(粘合符)

##可以将位于##两边的符号合成一个符号
它允许宏定义从分离的文本片段创建标识符
##又被称为记号粘合

例如:

//求两个数(不同类型的变量)的最大值
//定义了函数模版
#define a_MAX(type) \
type type_##MAX(type x,type y) \
{                            \
  return ((x>y)?x:y);         \
}                              

在这里插入图片描述
##和#算是冷门的知识点

拓展:
offsetof – 宏
计算结构体的成员的偏移量
是相较于首字节地址的偏移量
包含的头文件是 #include<stddef.h>
printf(结构体关键字,结构体成员名);

二.条件编译(很重要)

在编译一条指令时删除又可惜保留有碍事,那么我们可以选择有条件的编译

常见的条件编译指令:

1.单分子的条件编译
#if 常量表达式 //常量表达式由预处理器求值
  //使用      //条件如果为假(0),不参加编译,非0为真,参与编译
  //...
#endif
2.多分支的条件编译(跟ifelse差不多)
#if 常量表达式
//...
#elif 常量表达式
//...
#else
//...
#endif
3.判断是否被定义
#define MAX 1 //定义了MAX
#if defined(MAX)//执行
//...
#endif

#ifdef MAX //定义了MAX,执行
//...
#endif

#if !defined(MAX)//这两个都是如果未定义就执行
#ifndef MAX

4.嵌套指令(if else 的嵌套也差不多)
#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

三.命名约定

函数的命名和宏的命名非常相似
所以在语言上无法区分两者

1.宏名的命名

宏名全都大写(MAX)

2.函数的命名

函数名不全大写(Add)

四.#undef(用于移除一个宏定义)

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

int main()
{
	int a = 1;
	int b = 2;
	int ret = MAX(a, b);
    #undef MAX
	//MAX的宏定义被移除了,后面无法运行了
	int c = MAX(a, b);

	return 0;
}

五.命名行约定

许多编译器允许在命令行中定义符号(但是vs不允许,vscode可以),用于启动编译过程

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

int main()
{
  int arr[SIZE];//在命令行改变SIZE的大小,即可改变数组的大小
  int i = 0;
  for(i = 0;i < SIZE;i++)
  {
   arr[i] = i;
  }
  for(i = 0;i < SIZE;i++)
  {
   printf("%d ",arr[i]);
  }
  return 0;
}

六.头文件被包含的方式

1.本地文件包含

#include"filetest"

先在源文件(本工程路径)下查找,编译器再到标准库中去查找,再没找到就编译错误

vs环境下标准头文件的路径:
C:\Program Files (x86)\Microsoft Visual Studio 12.0 \VC\include (vs2013下的路径)

Linux环境下标准头文件的路径:
/usr/include

2.库文件包含

查找标准库下的头文件,就直接到标准库下查找
找不到就编译错误

本地文件包含可以用""吗?
答案是肯定的,但是这样做效率就低些,这样也不易于区分是库文件还是本地文件

3.嵌套文件包含(重复引入了同一个头文件)

//test.c
#include"test.h"
#include"test.h"
#include"test.h"

int main()
{
  //使用
  //...
  return 0;
}
//test.h
test();
//使用
//...

test.h头文件在test.c中被重复(多次)包含,那么test.h中的内容会被拷贝3份到test.c中
如果头文件的工程量比较巨大,这样被多次拷贝,后果将不堪设想
那么怎么解决这个问题呢?
可以使用条件编译

#ifndef __ TEST_H__ //如果没有这个文件为真就执行下面代码
#define __ TEST_H__//定义这个文件
//使用
//...
#endif
// 下次进入 #ifndef 为假(有这个文件了),不进入,一直为假
//只出现一份内容

包含一次头文件,判断一次#ifndef,第二次包含也是如此,如此往复
第一次包含头文件是没定义__TEST_H__的,所以会执行里面的代码,第二次已经定义了__TEST_H__ ,为假,不执行代码了,往后也不执行了

#pragma once
//就可以避免头文件的重复引用

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

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

相关文章

推特Twitter有直播功能吗?如何用Twitter直播?

现在各大直播平台已经成为社交媒体营销的一种重要渠道&#xff0c;它让品牌能够即时地与全球受众进行互动。据统计&#xff0c;直播市场正在迅速增长&#xff0c;预计到2028年将达到2230亿美元的规模。在这个不断扩张的市场中&#xff0c;许多社交媒体平台如YouTube、Facebook、…

消息队列的七种经典应用场景

在笔者心中&#xff0c;消息队列&#xff0c;缓存&#xff0c;分库分表是高并发解决方案三剑客。 在职业生涯中&#xff0c;笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。 这篇文章&#xff0c;笔者结合自己的真实经历&#xff0c;和大家分享…

在ROS上快速验证PID算法

在ROS上快速验证PID算法 前言 最近有在外面出差授课的工作任务&#xff0c;其中有一个环节是给大家讲述PID相关的内容&#xff0c;在制作相关PPT的时候查询了很多资料&#xff0c;但是写着写着突然意识到一个问题&#xff0c;PID已经在控制专业学习过程以及工程开发时间中那么…

量化交易入门(二十五)什么是RSI,原理和炒股实操

前面我们了解了KDJ&#xff0c;MACD&#xff0c;MTM三个技术指标&#xff0c;也进行了回测&#xff0c;结果有好有坏&#xff0c;今天我们来学习第四个指标RSI。RSI指标全称是相对强弱指标(Relative Strength Index),是通过比较一段时期内的平均收盘涨数和平均收盘跌数来分析市…

【YOLOv5改进系列(9)】高效涨点----使用CAM(上下文增强模块)替换掉yolov5中的SPPF模块

文章目录 &#x1f680;&#x1f680;&#x1f680;前言一、1️⃣ CAM模块详细介绍二、2️⃣CAM模块的三种融合模式三、3️⃣如何添加CAM模块3.1 &#x1f393; 添加CAM模块代码3.2 ✨添加yolov5s_CAM.yaml文件3.3 ⭐️修改yolo.py文相关文件 四、4️⃣实验结果4.1 &#x1f39…

HTB devvortex靶机记录

做这个靶机的师傅们我先提一句&#xff0c;不知道是否是因为网速还是其他因素影响&#xff0c;登录后台管理后&#xff0c;有大概率会被其他人挤下去&#xff0c;所以做这道题的师傅可以考虑在没人的时候去做。 打开靶场以后老规矩nmap扫一遍 这里爆出了80端口和22端口&#xf…

解决Veeam做Replication复制或备份任务并发数量少问题

Veeam执行replication复制或者备份任务时&#xff0c;一直都只有两个任务并发在跑&#xff0c;其他同时间任务只能等待前两个任务处理完才可以开始。 解决方法&#xff1a; 进入Veeam-Bacup Infrastructure-Backup Proxies&#xff0c;可以看到VMware Backup Proxy&#xff0…

【并发】第二篇 ThreadLocal详解

导航 一. ThreadLocal 简介二. ThreadLocal 源码解析1. get2. set3 .remove4. initialValue三. ThreadLocalMap 源码分析1. 构造方法2. getEntry()3. set()4. resize()5. expungeStaleEntries()6. cleanSomeSlots()7. nextIndex()8. remove()9. 总结ThreadLocalMap四. 内存泄漏…

@EnableWebMvc 导致自定义序列化器失效

目录 前言 一. 自定义序列化器失效 1.1 EnableWebMvc 的作用 1.2 EnableWebMvc 带来了什么后果 1.3 原理分析 1.4 问题解决 二. 总结 前言 在使用Swagger的时候用 到了EnableWebMvc&#xff0c;发现之前为了解决Long类型、日期类型等自定义序列化器失效了 Configurati…

TransformControls 是 Three.js 中的一个类,用于在网页中进行 3D 场景中物体的交互式操作。

demo案例 TransformControls 是 Three.js 中的一个类&#xff0c;用于在网页中进行 3D 场景中物体的交互式操作。让我们来详细讲解它的输入参数、输出、属性和方法&#xff1a; 输入参数&#xff1a; TransformControls 构造函数通常接受两个参数&#xff1a; camera&#…

企业培训系统功能介绍

在当今知识经济时代&#xff0c;企业的竞争力在很大程度上取决于员工的专业能力和综合素质。为了适应不断变化的市场需求和技术进步&#xff0c;企业需要对员工进行持续有效的培训。一个高效的企业培训系统对企业人才培训至关重要。以下介绍一下企业培训系统的主要功能&#xf…

【Qt 学习笔记】Day1 | Qt 开发环境的搭建

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Day1 | Qt 开发环境的搭建 文章编号&#xff1a;Qt 学习笔记 / 02 文…

下载huggingface中数据集/模型(保存到本地指定路径)

一. snapshot_download # 1.安装huggingface_hub # pip install huggingface_hubimport osfrom huggingface_hub import snapshot_downloadprint(downloading entire files...) # 注意&#xff0c;这种方式仍然保存在cache_dir中 snapshot_download(repo_id"ibrahimhamam…

线程池详解、核心参数、拒绝策略

什么是线程池 线程池是一种池化技术&#xff0c;它预先创建一组线程&#xff0c;用于执行异步任务。当有新任务到来时&#xff0c;线程池可以立即分配一个线程来处理&#xff0c;而不需要临时创建。这样可以减少因为频繁创建和销毁线程而导致的开销。 线程池的应用场景 高并…

【Go】五、流程控制

文章目录 1、if2、switch3、for4、for range5、break6、continue7、goto8、return 1、if 条件表达式左右的()是建议省略的if后面一定要有空格&#xff0c;和条件表达式分隔开来{ }一定不能省略if后面可以并列的加入变量的定义 if count : 20;count < 30 {fmt.Println(&quo…

前后端分离Springboot 整合使用activiti7教程(一)(全网最细)

activiti7关于SpringBoot前后端分离项目的详细教程 文章目录 activiti7关于SpringBoot前后端分离项目的详细教程一、Activiti工作流概述1.1 什么是工作流1.2 工作流应用场景1.3 什么是Activiti1.4 Activiti开发流程1.5 BPMN 2.0规范是什么1.6 BPMN 2.0 基本流程符号 二、Activi…

Java 实现扫描/识别图片文字 (OCR识别)

图片内容一般无法编辑&#xff0c;如果想要读取图片中的文本&#xff0c;我们需要用到OCR工具。本文将介绍如何在Java中实现OCR识别读取图片中的文字。 所需工具&#xff1a; IDEASpire.OCR for Java - Java OCR组件&#xff0c;支持识别多种语言、字体&#xff0c;可读取JPG、…

2024年大广赛联通沃派命题解析:赛题内容一览

2024大广赛又又又又又出新命题了&#xff0c;它就是助力青少年积极向上&#xff0c;乐观自信&#xff0c;探享多彩人生的5G时代潮牌——联通沃派&#xff0c;让我们来看看命题详情吧&#xff01; 联联通沃派是中国联通面向青少年群体推出的客户品牌&#xff0c;契合目标群体特…

module ‘numpy‘ has no attribute ‘int‘

在 NumPy 中&#xff0c;如果遇到了错误提示 "module numpy has no attribute int"&#xff0c;这通常意味着正在尝试以错误的方式使用 NumPy 的整数类型。从 NumPy 1.20 版本开始&#xff0c;numpy.int 已经不再是一个有效的属性&#xff0c;因为 NumPy 不再推荐使用…

win11 环境配置 之 Jmeter(JDK17版本)

一、安装 JDK 1. 安装 jdk 截至当前最新时间&#xff1a; 2024.3.27 jdk最新的版本 是 官网下载地址&#xff1a; https://www.oracle.com/java/technologies/downloads/ 建议下载 jdk17 另存为到该电脑的 D 盘下&#xff0c;新建jdk文件夹 开始安装到 jdk 文件夹下 2. 配…