#ifdefine #define #endif (避免头文件被重复包含的真正含义)
宏定义
首先在谈论正式话题之前,需要先介绍一个基础概念,也是前提,那就是宏定义。
#define demo 1
#define PI 3.14
我们都知道这样会将demo 在预处理阶段替换或者说展开为1,Pi 替换为3.14。
#define 宏定义一个标识符来表示一个常量。预处理所执行的操作就是简单的“文本”替换。
#include <stdio.h>也是这样的,即在预处理的时候先单纯地用头文件stdio.h中所有的“文本”内容替换程序中#include <stdio.h>这一行,然后再进行正式编译。
参考这个链接:
http://c.biancheng.net/view/187.html
条件编译
好了,知道这个概念以后我们就可以引入接下来这个概念,条件编译。
#if defined() || defined() || ...
#ifdef
#ifndef
#else if
#else
#endif
注意,我只是把可能遇见的所有条件编译宏列了一下,并不代表真正写的顺序就是这样。
至于#if defined 和#ifdef 的区别:
#if defined 就是#if 的一种用法,只不过后面跟了defined
对于#if后面需要是一个表达式,如果表达式为1则调用#if下面的代码。
比如:
#if defined(AA) || defined(BB) //和常规if一样,只是判断当前是否定义了AA,BB,用的是英文的过去时。defined 已经定义了。
#define WIDE_IN_SENSOR_ZOOM_LUX 390 //你的代码,可以写很多
code...
#endif
对于#ifdef后面需要的只是这个值有没有用#define定义,并不关心define的这个值是0还是1。
比如在上面这里这个例子,就可以接着这样写:
#if defined(AA) || defined(BB) //和常规if一样,只是判断当前是否定义了AA,BB,用的是英文的过去时。defined 已经定义了。
#define WIDE_IN_SENSOR_ZOOM_LUX 390 //你的代码,可以写很多
code...
#ifdef WIDE_IN_SENSOR_ZOOM_LUX //上面已经定义了WIDE_IN_SENSOR_ZOOM_LUX ,接着执行下面代码
code..
#endif //时刻注意每个条件都应该一个endif
#endif
还有一个区别就是,#ifdef 只能判断一个宏,如果判断多个宏只能用 #if defined() || defined () || defined ()
避免头文件被多次包含(预处理时重复include)
那么最后回到我们的正题,一般我们能在头文件看到最开始这样定义
#ifndef A_H //这个地方不需要和头文件名一样!理解这句话你就明白避免重复包含的真正含义了,而不是单纯记一个八股文知识点。
#defined A_H
code...
#endif
上面是通常的写法,一般重复包含指的是,
我们在a.cpp中
#include "a.h"
#include "b.h"
但是在a.h中我们又
#include "b.h"
这样在预处理阶段,展开#include "a.h" 时候会递归展开b.h, 然后#include "b.h"又展开一遍,这就是重复包含了。
虽然我们自己在写程序的时候,一般不会编译报错。因为我们写的都是小程序,并不是大型的工程,但是在大型工程中,可能会因为重复包含而编译出错。
回到上面,那么我们在头文件中使用这三行,就相当于一个开关!
比如在b.h中写上这三行。那么我们第一次展开a.h时候将b.h展开,然后就会判断是否定义 B_H 这个宏,然后定义,再执行代码。
#ifndef B_H
#defined B_H
code...
#endif
下一次再展开b.h时候,就会再次判断,但这是我们已经定义过了,就不会再次定义,也不会再次执行我们的代码,也就是不会再次在预处理阶段展开。
也就是不会在#include "b.h" 处再次将这一行替换为头文件中代码。因为#include "b.h" 在预处理阶段会替换为头文件中代码。
总结
所以总结来说就是用条件编译定义一个宏(作为一个开关),去判断是否include当前头文件。以此避免重复定义!
相关文章:
#ifdefine #define #endif (避免头文件被重复包含的真正含义)
宏定义 首先在谈论正式话题之前,需要先介绍一个基础概念,也是前提,那就是宏定义。 #define demo 1 #define PI 3.14我们都知道这样会将demo 在预处理阶段替换或者说展开为1,Pi 替换为3.14。 #define 宏定义一个标识符来表示一个…...
单片机能运行操作系统吗?
先直接上答案:可以!但是操作系统不是刚需,上操作系统比较占用单片机的资源,比如占用比较多的FLASH和RAM,间接增加了硬件成本,哪怕成本增加1毛钱,对于上量的产品,分分钟是一个工程师的…...
Python之webmagic爬虫优点与使用
一、webmagic的优点它更偏向于java的语法,对于熟悉java的工程师来说学习成本较低。提供多种选择器,如css选择器、xpath、正则等。有一个模块pipeline:可通过简单地配置,可以将爬虫抽取到的信息,持久化到文件、数据库等…...
代码随想录动态规划 || 121 122
Day42121. 买卖股票的最佳时机力扣题目链接给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。返…...
C++STL库中不可或缺的部分—string(模拟实现)
前文大家好,本篇文章主要是讲解一下string一些常用接口的模拟实现。众所周知,在日常生活中,字符串无处不在,如just do it,中国,一坤年等,想要在计算机上将这些字符展现出来就需要用到string类,而对我们C程序…...
MySQL复合查询
文章目录基本查询回顾多表查询自连接子查询单行子查询多行子查询多列子查询在from子句中使用子查询合并查询unionunion all基本查询回顾 查询的员工部门表结构: mysql> show tables; ----------------- | Tables_in_scott | ----------------- | dept …...
PCIe 资料收集2
文章目录感官认识PCIe的存储空间PCIe 在 linux 下的驱动PCIe 验证1.PCIe 传递裸数据2.PCIe 转其他设备PCIe转其他总线RS232USB从用户空间理解PCIe感官认识 总线协议接口 视频介绍PCIe 视频介绍及PCIe文字介绍 PCIe上可以接各种控制器硬盘控制器硬盘声卡控制器音响咪头/耳机显…...
Linux网络编程(使用VScode远程登录ubuntu)
文章目录 前言一、SSH插件的安装1.SSH简单介绍2.SSH插件安装和配置步骤二、安装C/C++插件总结前言 本篇文章将带大家进行网络编程的准备工作,使用vscode进行远程登录ubuntu。为什么要使用vscode进行远程登录ubantu呢?因为有些小伙伴的电脑可能性能不够开启虚拟机后会导致电脑…...
如何提高项目估算精准度?关键看5大影响因子
如何让项目估算工作更加精准,我们需要重点关注5大调整因子。 1、功能点调整因子 首先需要对功能点因子进行调整,区分不同类型的系统特征值。 因为不同的系统,对项目开发的影响程度不同,一般我们把系统特征值分为14种类型ÿ…...
论文阅读笔记《Nctr: Neighborhood Consensus Transformer for Feature Matching》
核心思想 本文提出一种融合邻域一致性的Transfomer结构来实现特征点的匹配(NCTR)。整个的实现流程和思想与SuperGlue相似,改进点在于考虑到了邻域一致性。邻域一致性在许多的传统图像匹配和图匹配任务中都有应用,他基于一个很重要…...
上位机系统Ubuntu 20.04与下位机arduino UNO通讯
目录一、安装arduino IDE1.1安装方法1.1.1终端里命令下载(不推荐)1.1.2官网下载(不推荐)1.1.3论坛下载(不推荐)1.1.4系统应用商店(推荐!)1.2配置项目文件位置1.3测试IDE功…...
hive面试题
1、什么是Hive Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能(HQL) 2、Hive的意义(最初研发的原因) 避免了去写MapReduce,提供快速开发的…...
【CUDA】《CUDA编程:基础与实践》CUDA加速的关键因素
CUDA事件计时 CUDA提供了一种基于CUDA事件(CUDA event)的计时方式,可用来给一段CUDA代码(可能包含主机代码和设备代码)计时。 对计时器的封装: class CUDATimeCost { public:void start() {elapsed_time_ 0.0;// 初始化cudaEventcheckCudaRuntime(cud…...
数据结构【Golang实现】(四)——双向循环链表
目录0. 定义节点1. IsEmpty()2. Length()3. AddFromHead()4. AddFromTail()5. Insert()6. DeleteHead()7. DeleteTail()8. Remove()9. RemoveByValue()10. Contain()11. Traverse()0. 定义节点 type DLNode struct {Data anyPrev, Next *DLNode }// DoublyLoopLinkedLis…...
【Redis】高可用架构之哨兵模式 - Sentinel
Redis 高可用架构之哨兵模式 - Sentinel1. 前言2. Redis Sentinel 哨兵集群搭建2.1 一主两从2.2 三个哨兵3. Redis Sentinel 原理剖析3.1 什么哨兵模式3.2 哨兵机制的主要任务3.2.1 监控(1)每1s发送一次 PING 命令(2)PING 命令的回…...
图片的美白与美化
博主简介 博主是一名大二学生,主攻人工智能研究。感谢让我们在CSDN相遇,博主致力于在这里分享关于人工智能,c,Python,爬虫等方面知识的分享。 如果有需要的小伙伴可以关注博主,博主会继续更新的,…...
面试官:关于CPU你了解多少?
CPU是如何执行程序的? 程序执行的基本过程 第一步,CPU 读取「程序计数器」的值,这个值是指令的内存地址,然后 CPU 的「控制单元」操作「地址总线」指定需要访问的内存地址,接着通知内存设备准备数据,数据准…...
UI自动化测试-Selenium的使用
文章目录 1. 环境搭建1.1 入门示例1.2 元素操作常用方法1.3 浏览器操作常用方法1.4 获取元素信息常用方法1.5 鼠标操作常用方法1.6 键盘操作常用方法1.7 下拉选择框操作2. 元素定位2.1 id定位2.2 name定位2.3 class_name定位2.4 tag_name定位2.5 link_text定位2.6 partail_link…...
嵌入式学习笔记——STM32的USART相关寄存器介绍及其配置
文章目录前言USART的相关寄存器介绍状态寄存器:USARTX->SR具体位代表的含义实际代码数据寄存器 USARTX->DR波特率寄存器 USARTX->BRR控制寄存器 (USART_CR)控制寄存器1(USART_CR1)控制寄存器2(USART_CR2)GPIO…...
Android setContentView流程分析(一)
对于做Android App的小伙伴来说setContentView这个方法再熟悉不过了,那么有多少小伙伴知道它的调用到底做了多少事情呢?下面就让我们来看看它背后的故事吧? setContentView()方法将分为两节来讲: 第一节:如何获取De…...
5分钟解锁B站视频解析:用开源工具实现自由播放的终极方案
5分钟解锁B站视频解析:用开源工具实现自由播放的终极方案 【免费下载链接】bilibili-parse bilibili Video API 项目地址: https://gitcode.com/gh_mirrors/bi/bilibili-parse 你知道吗?每次你在B站观看视频时,背后其实有一套精密的视…...
MRIcroGL如何让医学影像三维可视化变得简单高效?
MRIcroGL如何让医学影像三维可视化变得简单高效? 【免费下载链接】MRIcroGL v1.2 GLSL volume rendering. Able to view NIfTI, DICOM, MGH, MHD, NRRD, AFNI format images. 项目地址: https://gitcode.com/gh_mirrors/mr/MRIcroGL MRIcroGL是一款专业的开源…...
保姆级教程:用Vector CANoe搞定LIN诊断刷写自动化测试(附CAPL脚本思路)
从零构建LIN诊断刷写自动化测试:Vector CANoe实战指南 当汽车电子系统开始全面拥抱OTA升级浪潮时,LIN总线上的控制器也必须具备可靠的远程刷写能力。作为测试工程师,我们面临的挑战是如何在资源有限的LIN网络上,构建一个既能模拟…...
从单点到集群:我的SkyWalking 6.6.0 + ES7 + Nacos生产环境平滑升级踩坑记
从单点到集群:SkyWalking 6.6.0 ES7 Nacos生产环境平滑升级实战指南 去年春天,我们的电商大促监控系统突然告警——单节点SkyWalking服务器在流量洪峰下频繁崩溃。那一刻,我意识到单点架构已经成为业务增长的瓶颈。经过三个月的方案验证和灰…...
如何一站式破解Widevine DRM加密视频:智能解密工具完全指南
如何一站式破解Widevine DRM加密视频:智能解密工具完全指南 【免费下载链接】video_decrypter Decrypt video from a streaming site with MPEG-DASH Widevine DRM encryption. 项目地址: https://gitcode.com/gh_mirrors/vi/video_decrypter 还在为付费视频…...
VideoDownloadHelper实战指南:全网视频一键下载的高效方案
VideoDownloadHelper实战指南:全网视频一键下载的高效方案 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 还在为无法保存心仪的在…...
GPU可编程性演进与自动化架构设计解析
1. GPU可编程性演进史:从固定管线到通用计算的蜕变之路在计算机图形学发展的早期阶段,GPU采用的是完全固定功能的图形管线架构。这种架构将整个渲染流程固化在硬件中,开发者只能通过OpenGL等图形API调用预设功能,无法对渲染过程进…...
从混淆矩阵到mIOU:手把手解析语义分割核心评价指标
1. 从像素战场到成绩单:理解混淆矩阵 第一次接触语义分割任务时,我盯着那些五彩斑斓的分割图直发懵——怎么判断这个模型到底好不好?直到导师扔给我一张"混淆矩阵"的表格,才恍然大悟这就像学生时代的考试成绩单。想象你…...
GoAmzAI:开源本地化部署,AI赋能亚马逊卖家高效生成运营文案
1. 项目概述:一个面向亚马逊卖家的AI助手最近在和一些做跨境电商的朋友聊天,发现他们每天花在亚马逊店铺运营上的时间,很大一部分都耗在了重复性的文案工作上。从产品标题、五点描述、A页面,到广告文案、客户邮件回复,…...
在Node.js后端服务中集成多模型API以提升应用灵活性
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 在Node.js后端服务中集成多模型API以提升应用灵活性 对于需要构建智能客服或内容生成功能的Node.js开发者而言,依赖单一…...
