include 嵌套 重复 文件包含使用条件编译处理

知识点滴 - 关于头文件的重复包含问题 对于函数声明来说,如果一个编译单元里出现多次相同的声明没有问题,但如果是一个编译单元里对同一个对象(变量)或类型有多个定义,或者是同一个作用域里有重复定义,比如全局空间有重复定义,就会编译报错。重复包含一个头文件,可能会导致编译错误,就算头文件中都是可以重复出现的声明之类的内容,多次包含的话,也会增加预处理器或编译器的工作量,增加软件构建的时间。在一个源文件中包含此头文件my_include.h时,会检查此宏定义是否定义,如果是第一次包含,没有定义,则下一步定义这个宏,并将后面的内容包含进来。 阅读详情

          编译一个C程序涉及很多步骤。其中第1步被称为预处理。C预处理器在源代码编译之前进行一些文本性质的操作。它的主要任务包括删除注释、插入被#include指令包含的文件内容、定义和替换由#define指令定义的符号等。

          C和C++中都使用#include 指令包含头文件。#include 支持包含函数库文件和本地文件。

          我们在写一个小程序的时候,大多数情况下不会遇到这种嵌套包含的问题。但有些同学尝试使用多个头文件时,常会遇到“与‘**’类型冲突”的错误,最后不得将多个头文件合成一个。有些同学还会奇怪的问,为什么函数库头文件可以多次包含,而我的就不行呢?

让我们假设下面这种情况是一种比较简单的嵌套头文件包含情况:

a.h文件有一个结构体声明:mystruct

b.h 使用#include “a.h" 包含了a.h ,同时定义了一个函数print_b()

c.h 使用#include “a.h" 包含了a.h ,同时定义了一个函数print_c()

d.c 同时包含了 b.h 和c.h

关系如下图:


a.h


#include<stdlib.h>
#include<stdio.h>
#include<string.h>
typedef struct mystruct{
    char a[10];
}mystruct;

b.h

#include "a.h"
void print_b(){
    mystruct a;
    strcpy(a.a,"a.h");
    printf("this is in b.h %s\n",a.a);
}

c.h

#include "a.h"
void print_c(){
    mystruct c;
    strcpy(c.a,"a.h");
    printf("this is in c.h %s\n",c.a);
}

d.c

#include "b.h"
#include "c.h"
int main(){
    printf("this is in main\n");
    print_b();
    print_c();
    return 0;
}

gcc a.h b.h c.h d.c -o d.o 不能编译成功,有错误

# gcc a.h b.h c.h d.c -o d.o
In file included from c.h:1:0,
                 from d.c:2:
a.h:4:16: 错误: ‘struct mystruct’重定义
a.h:4:16: 附注: 原先在这里定义
a.h:6:2: 错误: 与‘mystruct’类型冲突
a.h:6:2: 附注: ‘mystruct’的上一个声明在此

原因是,预处理的时候,会读入整个头文件的内容,a.h的内容被重复包含了两次。出现了类型冲突。

在编译一个程序的时候,使用条件编译,你可以选择代码的一部分(或全部)是被正常编译还是完全忽略。这里,它就可以很好的派上用场。

替换a.h为下面内容

a.h

/*a.h*/
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#ifndef _a_H
#define _a_H 1
typedef struct mystruct{
    char a[10];
}mystruct;
#endif


gcc a.h b.h c.h d.c -o d.o

./d.o

this is in main
this is in b.h a.h
this is in c.h a.h


发现并没有类型冲突。

其实就是在a.h中使用了条件编译(这也是函数库头文件可以多次包含的原因)。

#ifndef _a_H 

#define _a_H 1

/*这是是你头文件本来的内容*/

#endif

这样多次重复包含的危险就被消除了。当头文件第一次被包含的时候,它正常处理,符号 _a_H( 可以自己定义符号 )被定义为 1(这个不是必须的,也可以直接写成#define _a_H)。如果头文件再次被包含时,通过条件编译,它说包含(#Iinfdef ...#endif 之间)的内容就会被忽略。


这里的示例只是为了更清楚的看到条件编译的作用,所以只在a.h当中使用了,其实如果我们所有头文件都是要上述的条件编译的方法编写,就可以消除多次包含的危险。因为其他人使用你的头文件的时候,可能并不清楚它已经包含了多少其他文件。(最好能够尽避免多次包含,因为预处理仍会读入整个头文件,即使它已经被忽略)


当然条件编译的作用不仅仅于此,比如在编写程序的时候需要debug的时候要经常用到。一些debug在编写程序阶段需要,当交付是有不需要让他们输出,这时候条件编译就大有用处。(下面是我常用的,注意这是使用的是#ifdef)

/*#define DEBUG_MIGRATION
*/
#ifdef DEBUG_MIGRATION
#ifdef CONFIG_LINUX
#include <sys/syscall.h>
#define DPRINTF(fmt, ...)                                               \
    do {                                                                \
        printf("%d:%ld %s:%d: " fmt, getpid(), syscall(SYS_gettid),     \
               __func__, __LINE__, ## __VA_ARGS__);                     \
    } while (0)
#else
#define DPRINTF(fmt, ...)                                               \
    do {                                                                \
        printf("%s:%d: " fmt, __func__, __LINE__, ## __VA_ARGS__);      \
    } while (0)
#endif
#else
#define DPRINTF(fmt, ...)       do { } while (0)
#endif


需要输出debug的时候就#define DEBUG_MIGRATION ,不需要的时候就注释它,那么整个文件的debug信息就不会输出。

下面是使用的范例:

DPRINTF("flushed %zu of %zu byte(s)\n", offset, s->buffer_size);
需要输出debug的地方就使用DPRINTF。

常用的语法形式如下:

#if constant-expression
      statements
#elseif constant-expression
      statements2
#else
      other statements
#endif

常用的判断是否被定义的有

#ifndef   something/* something 没有被定义*/

#ifdef     something/*something 已经被定义*/


参考:

pointers on c, Kenneth A.Reek

QEMU/KVM源码


caffe深度学习【十】编译错误:In file included from ./include/caffe/util/device_alternate.hpp:40:0, 早上想跑一下目标检测RON算法 https://github.com/taokong/RON   git下来之后,要编译他的caffe时,出现如下问题: PROTOC src/caffe/proto/caffe.proto CXX .build_release/src/caffe/proto/caffe.pb.cc CXX src/caffe/solvers/adadelta_solve... 阅读详情

相关推荐

文件包含漏洞(DVWA靶场文件包含漏洞详解)

浏览器中运行此日志文件,即可执行插入的PHP代码。注意:若是一句话代码,就可以控制此服务器了。查看日志文件已记录此条信息。1、文件包含漏洞形成原因。2、文件包含漏洞的分类。3、PHP包含日志文件。

tmzy1的博客 2532

头文件互相包含解决_【C语言】- 预处理指令3 - 文件包含

这篇小文介绍最后一个预处理指令---文件包含一、基本概念其实我们早就有接触文件包含这个指令了, 就是#include,它可以将一个文件的全部内容拷贝另一个文件中。二、一般形式1、第1种形式#include <文件名>直接到C语言库函数头文件所在的目录中寻找文件2、第2种形式 #include "文件名"系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到...

weixin_39950470的博客 976

C/C++ 头文件防卫:告别重复定义错误,掌握 #include Guards 与 #pragma once

在C/C++项目开发中,头文件重复包含是一个常见问题,可能导致编译错误。重复包含通常发生在直接或间接多次包含同一个头文件时,尤其是当头文件中包含变量、结构体或枚举定义时。为了解决这一问题,C/C++提供了两种主要方法:Include Guards和#pragma once。Include Guards通过宏定义和条件编译指令确保头文件内容只被处理一次,而#pragma once则是一个非标准但广泛支持的指令,直接告诉编译器头文件只需包含一次。选择哪种方法取决于项目需求和编译器支持,Include Guard

Web安全工具库 1690

避免同一个文件被include多次

百度问题:(转自:http://zhidao.baidu.com/question/112685790.html?si=1)我们知道c++有时会遇到防止头文件重复include问题,常用的方式可以防止.h文件重复include 的方式为:#if !defined...#define... 但是在有些地方发现了这段代码#if _MSC_VER > 1000#pragma once#e

bdewang的专栏 1207

【电磁场与电磁波课程设计】基于HFSS的双频微带天线仿真及设计

第五代移动通信技术(5G)的商用已经近在眼前,作为移动通信中最为重要的功能组件,面向5G通信应用的手机天线与基站天线的技术研究与设计成为近年来的热点。随着移动通信中“跳频”“扩频”等通信技术发展,为了满足与多个终端的通信要求,实现多系统共用和收发共用等功能,这就要求天线在不同频段下工作。根据国家工信部的最新规定,5G移动通信的中频段被划定在3.3 GHz-3.5 GHz及4.8 GHz-5.0 GH,面向5G移动通信的天线应具有高增益、小型化、宽频段及高隔离度等技术特征,以满足5G通信的高传输速率、波束智能

weixin_44450575的博客 1万+

内网环境下 OpenSSL 与 OpenSSH 安全升级实战指南:从 9.9p2 离线部署到回滚方案

本文详细介绍了内网环境下OpenSSL与OpenSSH的安全升级实战指南,重点涵盖从9.9p2版本离线部署到回滚方案的全流程。通过备份策略、动态库处理、权限修复等关键步骤,确保升级过程安全可靠,特别适合金融、政务等敏感行业的内网服务器安全加固。

weixin_30566063的博客 511

漫谈:C C++ 嵌套包含与前置声明

漫谈:C C++ 嵌套包含与前置声明

编程之道在明明德在亲民在止于至善 1562

Simscape Multiboby学习笔记1——跟着官网学Multibody

文章目录一. 引言二. Simscape Multibody自学之路三. 本教程的目录 一. 引言 最近在倒腾Matlab的动力学仿真,起因是看到有人推荐Matlab的multbody模块,一经了解之下简直惊为天人。作为一名Matlab的小粉,看到这么好用的模块简直不要太开心,之前用simulink搭飞行器的仿真模型,虽然能够仿真看到六自由度位移,毕竟不能可视化,还是很不够直观,而且simulink仿真(以及更费力的脚本文件仿真)需要精确建模,模型不精确计算也是天差地别。而Multibody在具备其他动力学

qq_30267617的博客 8241

C/C++基础 -- 预处理命令(宏定义、文件包含、条件编译)

C/C++基础 -- 预处理命令1、预处理命令2、宏定义2.1、不带参数的宏定义2.2、带参数的宏定义3、# 和 ## 预处理运算3.1、# 预处理运算符3.2、## 预处理运算符4、文件包含 本博文由 西北工业大学MOOC 总结而来,以备以后回顾。(侵删) 1、预处理命令 什么是预处理命令   在C++文件中,只要是以 “#” 开头的命令都称为预处理命令。   预处理命令不是C++本身的组成...

不世峰兄 的博客 2929

LAMMPS GCMC模拟保姆级教程:从fix gcmc命令到吸附等温线实战

本文提供LAMMPS GCMC模拟的详细教程,从fix gcmc命令设置到吸附等温线实战,涵盖巨正则蒙特卡洛模拟的全流程。通过MOF-5吸附甲烷的案例,指导用户构建模拟体系、转换化学势与压力、定义GCMC区域,并绘制出版级吸附等温线,助力材料科学研究。

weixin_33724046的博客 604

l0phtcrack 7(爆破管理员密码)使用教程

l0phtcrack7简称lc7,是爆破计算机管理员密码的软件,早期是网络安全管理员用来检测系统用户是否使用了不安全的密码,后被黑客用于用户口令破解 功能:该工具支持远程破解,理论上能破解所有密码,但对复杂度比较高的密码,破解时间很长 使用前提:1.登录了需要破解的计算机 2.知道需要破解的计算机的一个管理员的账户,密码 ** 也许你会疑惑,我都知道了一个管理员账户密码了,还要另外的管理员密码...

Xiongcanne的博客 2万+

(二十三) 23.2 文件包含和条件编译

(二十三) 23.2 文件包含和条件编译

lcc1737的博客 257

Open3D 基于法线的双边滤波

基于法线的双边滤波是一种用于点云平滑的技术,它结合了点与其邻域点之间的几何距离和法线方向的相似性,从而在去除噪声的同时保留几何特征。这种滤波方法广泛应用于点云处理领域,尤其是在需要保留表面细节和边缘的场景中。

纵马踏花向自由 2500

C++报错无效的预处理命令include_C++日志(十七)编译预处理

1、#include命令文件包含所使用的“#include”命令,目的是将另一个源文件嵌入到本源文件中,其形式包含下面两种:使用#include<文件名>形式,在系统目录下进行搜索;使用#include"文件名"形式,先在当前目录进行搜索,搜索不到转到系统目录下搜索;最后,#include指令支持嵌套使用,即xxx.h文件中仍可以使用#include指令包含其它的.h文件。2、#def...

weixin_39782832的博客 1363

费雪的未来增长评估:预测颠覆性技术的影响

本文旨在提供一个系统性的框架,用于评估和预测颠覆性技术的增长轨迹。我们将重点关注费雪增长模型(Fisher-Pry Model)这一经典技术扩散理论,探讨其在现代技术预测中的应用价值。文章首先介绍费雪增长模型的基本概念,然后深入其数学原理和算法实现。随后展示实际应用案例,讨论工具资源,最后探讨未来发展趋势。每个部分都包含详细的技术实现和理论分析。费雪增长模型(Fisher-Pry Model):一种描述技术替代过程的S型增长模型,用于预测新技术取代旧技术的速率。

欢迎来到我的优快云空间!这里聚焦AI大模型应用实战,分享前沿技术、实战案例与开发经验。 928

(论文加源码)基于CNN和LSTM的脑电情绪识别(数据集为DEAP和seed)

论文及源码见个人主页:https://download.youkuaiyun.com/download/qq_45874683/84118637?spm=1001.2014.3001.5503 (论文加源码)基于CNN和LSTM的脑电情绪识别(数据集为DEAP和seed)4D-CRNN 目录 目录: 运行过程: 1. 运行1D文件(没有什么bug): 2. 再运行3D文件(没有出现bug): 3. 最后运行main文件(出现了两个bug)(前提需要配置好tensorflow的框架): 第一个bug是..

qq_45874683的博客 6366

c语言include不起作用,c语言中include的使用方法

c语言中include的使用方法发布时间:2020-06-16 09:09:37来源:亿速云阅读:185作者:Leah这篇文章将为大家详细讲解有关c语言中include的使用方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1、#include 命令介绍#include 命令是预处理命令的一种,预处理命令可以将别的源代码内容插入到所指定的位置;可以标识出只有在特...

weixin_33605464的博客 2038

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

【C语言】17-预处理指令3-文件包含

一、基本概念 其实我们早就有接触文件包含这个指令了, 就是#include,它可以将一个文件的全部内容拷贝另一个文件中。   回到顶部 二、一般形式 1.第1种形式#include  直接到C语言库函数头文件所在的目录中寻找文件   2.第2种形式 #include "文件名" 系统会先在源程序当前目录下寻找,若找不到,再到操作系统的pat

u013948187的专栏 393

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

include、require、include_once、require_once的区别

include、require、include_once、require_once的区别

资深系统架构,深耕高并发研发与 AI 大模型工程化落地。技术栈以 Python (AI/NLP/RAG/Agent) 与 Golang (高并发架构) 为双核心,兼具 PHP 大型应用经验。专注算法落地、复杂系统设计及团队技术赋能 2058

C++预处理中的“文件包含”功能(#include)

所谓“文件包含”,是指一个文件可以将另外一个文件的全部内容包含进来,也就是将另外的文件包含到本文件中。C++语言中,通过 #include 命令来实现。其一般形式如下: 虽然可以用#include把任何一个其他文件的内容包含到当前文件中,但是在C++语言中,最常见的做法还是一些源程序文件(扩展名为.c或者.cpp等)用#include把一些头文件(扩展名为.h或者.hpp等)包含进来,这种包含的感觉如图1所示。 图 1 用 #include 将 head.h 内容包含到 a.cp

m0_51073072的博客 570

PHP学习之文件包含

PHP学习之文件包含 定义与产生 在项目实践中,有很多的代码需要重复调用,这是只要将需要重复调用的代码写在一个文件当中,重复调用这个文件就好。 分类 动态、静态:输入内容用户是否可控 远程、本地:文件源在哪里 向上、向下:被包含文件是作为文件源,还是输出通道 主要函数 include :包含并执行文件 include_once 与include相同,区别在于会自动判断是否某个文件,一个文件只包含一次 require require_once require 、require_once 与in

weixin_45960266的博客 296

ABAP结构体嵌套实战:INCLUDE TYPE和INCLUDE STRUCTURE的5个典型应用场景

本文深入探讨了ABAP中结构体嵌套技术INCLUDE TYPE和INCLUDE STRUCTURE的5个典型应用场景,包括基础数据结构复用、多源数据结构合并、带前缀/后缀的字段复用、动态结构扩展和类型安全的嵌套结构。通过实际代码示例展示了如何高效处理复杂数据结构,提升代码复用性和可维护性,是ABAP开发者必备的核心技能。

weixin_30485379的博客 443

Daily-C-Study(17):C语言文件包含#include

Daily-C-Study(17):C语言文件包含#include 成于坚持,败于止步 文件包含是预处理的一个重要功能,它可用来把多个源文件连接成一个源文件进行编译,结果将生成一个目标文件。C语言提供#include 命令来实现文件包含的操作,它实际是宏替换的延伸,有两种格式: 一、#include 其中,filename 为要包含的文件名称,用尖括号括起来,也称为头文件,表示预处理到系统规定的...

Ryze的博客 501

【C语言】15 预处理指令--文件包含

1.基本概念 其实我们早就有接触文件包含这个指令了,就是#include,它可以将一个文件的全部内容拷贝另一个文件中。   2.一般形式 1.第1种形式#include  直接到C语言库函数头文件所在的目录中寻找文件   2.第2种形式 #include "文件名" 系统会先在源程序当前目录下寻找,若找不到,再到操作系统的path路径中查找,最后才到C语言库函数头文件所在目录中查找   3.使用注

LiJin 653

php基础-文件包含(第13天)

摘要:PHP文件包含功能允许在一个脚本中引入另一个文件,实现代码复用和分工协作。主要包含四种形式:include/include_once和require/require_once,区别在于错误处理方式及是否重复包含。文件加载时会被嵌入到包含位置,并单独编译。路径分为绝对路径和相对路径,各有优缺点;嵌套包含时建议使用__DIR__或绝对路径避免相对路径错误。核心原则:必需文件用require,可选文件用include,优先使用_once版本确保安全。

weixin_48813932的博客 709

PHP 文件包含、文件加载、文件路径、文件嵌套包含

1. 2.在PHP中被包含的文件是单独进行编译的 3. 4.include和require都是文件包含,区别在于报错不一样。include获取不到文件,可以继续执行下面的语句,而require不行。 5.include可以执行多次,而include_once只允许执行一次 6....

liuyi0604的博客 959
上一篇: 1053. Path of Equal Weight (30)-PAT
下一篇: 1052. Linked List Sorting (25)-PAT
zoushidexing
博客等级 码龄18年 70粉丝 171原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值