关于C/C++语言重复包含头文件,编译时报错已定义的宏未定义的原因及解决方法

news2025/1/23 10:21:19

在编写一个文件较多的单片机程序时,为了在一个文件中定义的变量或宏能被另一个文件使用,经常会写成在多个头文件相互包含,由此将可能会导致明明已经定义的宏,且已经将宏所在的文件使用 #include  包含,编译时仍会报错未定义。

先来看一段简单的代码

main.c

#include "main.h"

void SystemInit(void)
{

}

int main(void)
{

}

main.h

#ifndef __MAIN_H_
#define __MAIN_H_





#endif

lk.c

#include "lk.h"


unsigned char Admin_num;

lk.h

#ifndef __LK_H_
#define __LK_H_

#include "head.h"


#define MAX_LEN (32)
#define KEY_LEN (32)


#endif

fp.c

#include "fp.h"




FP_TypeDef User_Data;

fp.h

#ifndef __FP_H_
#define __FP_H_

#include "head.h"


typedef struct
{
	unsigned char id;
	unsigned char key[MAX_LEN];

}FP_TypeDef;



#endif



head.h 

#ifndef __HEAD_H_
#define __HEAD_H_

#include "fp.h"
#include "lk.h"


#endif

此时编译将会报错 ,提示在fp.h文件中 MAX_LEN  没有定义

 

 我们单个C文件编译,发现,fp.c能通过, lk.c 文件居然报错

lk.c 看上去并没有什么错误为什么会报错呢,而且fp.h文件中用到的  MAX_LEN  已经通过head.h文件将 lk.h文件包含进入,MAX_LEN 是在lk.h文件中定义的,为什么还会提示在fp.h文件中未定义MAX_LEN  ??

原因分析

我们将 lk.c 中所有的 #include  全部用对应的头文件层层替换,得到的代码为:

 1、lk.c原文

#include "lk.h"


unsigned char Admin_num;

 2、用lk.h 中的内容替换 #include "lk.h"

//#ifndef __LK_H_   //前面没有定义过__LK_H_,所以编译 #ifndef 到 #endif 的内容
#define __LK_H_

#include "head.h"


#define MAX_LEN (32)
#define KEY_LEN (32)


//#endif


unsigned char Admin_num;

 3、用head.h 中的内容替换 #include "head.h" 

//#ifndef __LK_H_   //前面没有定义过 __LK_H_,所以编译 #ifndef 到 #endif 的内容
#define __LK_H_

//#ifndef __HEAD_H_	//前面没有定义过 __HEAD_H_,所以编译 #ifndef 到 #endif 的内容
#define __HEAD_H_

#include "fp.h"
#include "lk.h"


//#endif


#define MAX_LEN (32)
#define KEY_LEN (32)


//#endif


unsigned char Admin_num;

 4、用fp.h 中的内容替换 #include "fp.h" 

//#ifndef __LK_H_   //前面没有定义过 __LK_H_,所以编译 #ifndef 到 #endif 的内容
#define __LK_H_

//#ifndef __HEAD_H_	 //前面没有定义过 __HEAD_H_,所以编译 #ifndef 到 #endif 的内容
#define __HEAD_H_


//#ifndef __FP_H_   //前面没有定义过 __FP_H_,所以编译 #ifndef 到 #endif 的内容
#define __FP_H_

#include "head.h"


typedef struct
{
	unsigned char id;
	unsigned char key[MAX_LEN];

}FP_TypeDef;



//#endif



#include "lk.h"


//#endif


#define MAX_LEN (32)
#define KEY_LEN (32)


//#endif


unsigned char Admin_num;

 5、用head.h 中的内容替换 #include "head.h" 

//#ifndef __LK_H_   //前面没有定义过 __LK_H_,所以编译 #ifndef 到 #endif 的内容
#define __LK_H_

//#ifndef __HEAD_H_	 //前面没有定义过 __HEAD_H_,所以编译 #ifndef 到 #endif 的内容
#define __HEAD_H_


//#ifndef __FP_H_   //前面没有定义过 __FP_H_,所以编译 #ifndef 到 #endif 的内容
#define __FP_H_

//#ifndef __HEAD_H_   //前面已经定义过 __HEAD_H_,所以不再编译 #ifndef 到 #endif 的内容
/*#define __HEAD_H_

#include "fp.h"
#include "lk.h"
*/

//#endif




typedef struct
{
	unsigned char id;
	unsigned char key[MAX_LEN];

}FP_TypeDef;



//#endif



#include "lk.h"


//#endif


#define MAX_LEN (32)
#define KEY_LEN (32)


//#endif


unsigned char Admin_num;

 6、用lk.h 中的内容替换 #include "lk.h"

//#ifndef __LK_H_   //前面没有定义过 __LK_H_,所以编译 #ifndef 到 #endif 的内容
#define __LK_H_

//#ifndef __HEAD_H_	 //前面没有定义过 __HEAD_H_,所以编译 #ifndef 到 #endif 的内容
#define __HEAD_H_


//#ifndef __FP_H_   //前面没有定义过 __FP_H_,所以编译 #ifndef 到 #endif 的内容
#define __FP_H_

//#ifndef __HEAD_H_   //前面已经定义过 __HEAD_H_,所以不再编译 #ifndef 到 #endif 的内容
/*#define __HEAD_H_

#include "fp.h"
#include "lk.h"
*/

//#endif




typedef struct
{
	unsigned char id;
	unsigned char key[MAX_LEN];

}FP_TypeDef;



//#endif



//#ifndef __LK_H_  //前面已经定义过 __LK_H_,所以不再编译 #ifndef 到 #endif 的内容
/*#define __LK_H_

#include "head.h"


#define MAX_LEN (32)
#define KEY_LEN (32)
*/

//#endif


//#endif


#define MAX_LEN (32)
#define KEY_LEN (32)


//#endif


unsigned char Admin_num;

7、去掉所有注释,lk.c中最终的内容为:


#define __LK_H_
#define __HEAD_H_
#define __FP_H_


typedef struct
{
	unsigned char id;
	unsigned char key[MAX_LEN];

}FP_TypeDef;



#define MAX_LEN (32)
#define KEY_LEN (32)


unsigned char Admin_num;

可以发现, 结构体中用到的  MAX_LEN   在前面并没有定义,而是在后面定义的,最终导致编译错误。

重复包含头文件,会使后面定义的内容,被前面的条件编译忽略,导致不被编译。

解决方法

将 #include  语句放在所有宏定义之后

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

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

相关文章

自学大语言模型的应用程序框架Langchain(初入门)

现阶段chatGPT非常火热。带动了第三方开源库:LangChain火热。它是一个在大语言模型基础上实现联网搜索并给出回答、总结 PDF 文档、基于某个 Youtube 视频进行问答等等的功能的应用程序。 什么是Langchain LangChain 是一个用于开发由语言模型驱动的应用程序的框架…

Vue 3.3 浪客剑心

✅创作者&#xff1a;陈书予 &#x1f389;个人主页&#xff1a;陈书予的个人主页 &#x1f341;陈书予的个人社区&#xff0c;欢迎你的加入: 陈书予的社区 &#x1f31f;专栏地址: 三十天精通 Vue 3 文章目录 特征弃用一、 < s c r i p t s e t u p > <script setup…

【啃书C++Primer5】-编写一个简单C++程序

每个C程序都包含一个或多个函数(function)&#xff0c;其中一个必须命名为main。操作系统通过调用main来运行C程序。下面是一个非常简单的main函数&#xff0c;它什么也不干&#xff0c;只是返回给操作系统一个值: int main() {return 0; }一个函数的定义包含四部分:返回类型(r…

【讨论话题】 工作中应不应该出于好心,帮助同事完成不属于你职责范围内的问题?

前言 职场如战场&#xff0c;职场中经常有一种好心帮忙反而成了义务的乱相存在。我们要做一个好人&#xff0c;同事要防备一些坏人。 勿以善小而不为&#xff0c;勿以恶小而为之 文章目录 前言社群内部讨论社群内部讨论总结师父的回答如何优雅的说不总结 社群内部讨论 先来看…

声音合成——Foley Sound——DECASE项目——多模态智能感知与应用——代码实现(6)

文章目录 概述encoder的编写过程代码编写运行结果问题总结 decoder的编写过程知识补充关于逆卷积 代码编写运行结果总结 Autoencoder模型编写 compile方法 train方法 保存和加载模型模块编写实现代码——autoencoder代码实现代码——train代码实现代码——保存和加载模型的代…

GPT-4最强竞品迎来重磅升级:一次10万token,百页资料一分钟总结完毕

夕小瑶科技说 分享 来源 | 量子位 作者 | 丰色 萧箫 号称ChatGPT“最强竞争对手”的Claude&#xff0c;今天迎来史诗级更新—— 模型记忆力原地起飞&#xff0c;现在1分钟看完一本数万字的小说&#xff0c;已经不在话下。 消息一出&#xff0c;评论区直接炸了&#xff0c;网友…

HTTP第九讲——你能写出正确的网址吗?

应该用什么来标记服务器上的资源呢&#xff1f;怎么区分“这个”资源和“那个”资源呢&#xff1f; 用的是 URI&#xff0c;也就是统一资源标识符&#xff08;Uniform Resource Identifier&#xff09;。因为它经常出现在浏览器的地址栏里&#xff0c;所以俗称为“网络地址”&a…

猫妹人生中的第一张Python证书长这样(1)

小朋友们好&#xff0c;大朋友们好&#xff01; 我是猫妹&#xff0c;一名爱上Python编程的小学生。 欢迎和猫妹一起&#xff0c;快乐学习&#xff0c;茁壮成长&#xff01; 猫妹和她的朋友们 猫妹和她的朋友们有两层含义。 一是新的合集名称&#xff0c;在这个合集里面&am…

redis从零开始(3)----基本类型hyperloglog/geo/stream

接上文 redis基本类型 HyperLogLog 简介 HyperLogLog是用于「统计基数」的数据集合类型&#xff0c;基数统计就是指统计一个集合中不重复的元素个数&#xff0c; 但是准确率不是百分百&#xff0c;即他可以提供不精确的去重计数。HyperLogLog 的优点是&#xff0c;在输入元素…

.Net平台下OpenGL绘制图形(1)(VS2019,Winform,C#)

1、介绍 OpenGL&#xff08;英语&#xff1a;Open Graphics Library&#xff0c;译名&#xff1a;开放图形库或者“开放式图形库”&#xff09;是用于渲染2D、3D矢量图形的跨语言、跨平台的应用程序编程接口&#xff08;API&#xff09;。这个接口由近350个不同的函数调用组成…

【图解KMP算法】

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 找出字符串中第一个匹配项的下标 1.什么是KMP…

Windows 下 VMware 虚拟机的 vmdk 文件的压缩

在 Windows 下玩虚拟机&#xff0c;一般大家都会安装 VMware 软件&#xff0c;然后通过软件安装其它操作系统环境&#xff08;如 Linux&#xff09;来模拟各个服务器环境。然而大家在使用过程中可以发现这样一个问题&#xff0c;那就是每个操作系统对应主机磁盘目录中&#xff…

与小我11岁的人一次PK

基本情况 时间过得很快&#xff0c;如同流水一般。 我的同事F已经离职一段时间了&#xff0c;怎么说呢&#xff1f; 公司领导的想让我们进行PK,谁是胜利者&#xff0c;谁留下&#xff0c;这的确与别的公司不同&#xff0c;别的公司通过面试&#xff0c;公司领导感觉那样不足体…

STC15单片机+nRF24L01硬件SPI通讯

STC15单片机+nRF24L01硬件SPI通讯 📍相关篇《STC15单片机+nRF24L01通讯利用PCA输入捕获触发》🔖验证对象:STC15L2K60S2📍STC15L2K60S2自制系统板硬件开源地址:https://oshwhub.com/perseverance51/stc15l2k60s2-ji-tong-ban⏱时钟频率:11.0592MHz🌼NRF24L01模块以及…

C#串口通信从入门到精通(11)——串口接收的数据存储到本地文件(txt、csv)

文章目录 前言一、将数据以CSV格式进行存储二、将数据以TXT格式进行存储三、全部代码前言 我们在串口通信程序开发中经常需要将串口接收到的数据存储到本地电脑,本文就来介绍如何在串口通信中将数据进行存储 一、将数据以CSV格式进行存储 我们将软件选择为csv文件存储,如下…

搭建React Native开发环境

1.安装node node.js官网 需要确定自己安装的版本是否是12版本以上 node -v 2.安装yarn npm install -g yarn 3.安装 Android Studio 这是官网推荐的安装地址: android studio 国内用户可能无法打开官方链接&#xff0c;请自行使用搜索引擎搜索可用的下载链接。安装界面中选…

一个27岁妹子的软件测试之路

艰难的测试之路 2023年&#xff0c;现在这个大环境下&#xff0c;软件测试行业卷麻了&#xff0c;应该说不仅仅软件测试这行&#xff0c;而是整个IT行业都卷麻了&#xff0c;但最卷的还是前端&#xff0c;真的是卷的发紫&#xff0c;今天想和大家聊聊我认识的一个妹子&#xf…

基于SpringBoot+Mybatis-plus+Myslq+ElementVue大学生健康档案管理系统

基于SpringBootMybatisMyslqElementVue大学生健康档案管理系统 一、系统介绍1、系统主要功能&#xff1a;2.涉及技术框架&#xff1a;3.本项目所用环境&#xff1a; 二、功能展示三、其它系统四、获取源码 一、系统介绍 1、系统主要功能&#xff1a; 项目分为个人信息、个人健…

使用 @Autowired 依赖注入时警告不建议使用字段注入

文章目录 字段注入缺点无法注入 final 字段与 Spring 容器耦合度高 构造器注入&#xff08;Spring 官方推荐&#xff09;Setter 方法注入 在 Spring 中注入依赖时有字段注入、构造器注入、Setter 方法注入三种注入方式。 字段注入缺点 无法注入 final 字段 在 Spring 2.5 中引…

【C++】8.编译:CMake工具入门

&#x1f60f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f60f;这篇文章主要介绍CMake工具的入门使用。————————————————学其所用&#xff0c;用其所学。——梁启超————————————————— 欢迎来到我的博客&#xff0c;一起学习知识…