c,c++里面,头文件里面的ifndef /define/endif的作用

2023-10-09 20:33

本文主要是介绍c,c++里面,头文件里面的ifndef /define/endif的作用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

  是关于头文件里面的一些地方:

例如:要编写头文件test.h

         在头文件开头写上两行:

          #ifndef _TEST_H

          #define _TEST_H//一般是文件名的大写

         ············

         ············

         头文件结尾写上一行:

          #endif

    大概是以前没有学好吧,对这里不是很理解,为什么要用这些呢?刚才上网查了查,借鉴了点高手的,自己总结了一点,就写在这里了,有什么错误之处,请大侠们指出

    1.比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。

例如:

假设你的工程里面有4个文件,分别是a.cpp,b.h,c.h,d.h。  
a.cpp的头部是:  
#include   "b.h "  
#include   "c.h "  
b.h和c.h的头部都是:  
#include   "d.h "  
而d.h里面有class   D的定义。  
这样一来,  
编译器编译a.cpp的时候,先根据#include   "b.h "去编译b.h这个问题,再根据b.h里面的#include   "d.h ",去编译d.h的这个文件,这样就把d.h里面的class   D编译了;  
然后再根据a.cpp的第二句#include   "c.h ",去编译c.h,最终还是会找到的d.h里面的class   D,但是class   D之前已经编译过了,所以就会报重定义错误。 加上ifndef/define/endif,就可以防止这种重定义错误。

所以还是把头文件的内容都放在#ifndef和#endif中吧。  
不管你的头文件会不会被多个文件引用,你都要加上这个。  
一般格式是这样的:   
#ifndef   <标识 >   
#define   <标识 >   
......   
......   
#endif   <标识 >  
在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h   
#ifndef   _STDIO_H_   
#define   _STDIO_H_   
......   
#endif  

 
2.在#ifndef中定义变量出现的问题(一般不定义在#ifndef中)。   
#ifndef   AAA   
#define   AAA   
...   
int   i;   
...   
#endif   
里面有一个变量定义在vc中链接时就出现了i重复定义的错误,而在c中成功编译。   
原因:   
(1).当你第一个使用这个头的.cpp文件生成.obj的时候,int   i   在里面定义了当另外一个使用这个的.cpp再次[单独]生成.obj的时候,int   i   又被定义然后两个obj被另外一个.cpp也include   这个头的,连接在一起,就会出现重复定义.   (2).把源程序文件扩展名改成.c后,VC按照C语言的语法对源程序进行编译,而不是C++。在C语言中,若是遇到多个int   i,则自动认为其中一个是定义,其他的是声明。 

  
(3).C语言和C++语言连接结果不同,可能(猜测)时在进行编译的时候,C++语言将全局变量默认为强符号,所以连接出错。C语言则依照是否初始化进行强弱的判断的。  
(参考解决方法:   
(1).把源程序文件扩展名改成.c。   
(2).推荐解决方案:   .h中只声明   extern   int   i;  
        在.cpp中定义   
#ifndef   __X_H__   
#define   __X_H__   
extern   int   i;   
#endif   //__X_H__   int   i;   
注意问题:变量一般不要定义在.h文件中。

这篇关于c,c++里面,头文件里面的ifndef /define/endif的作用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/175397

相关文章

C++右移运算符的一个小坑及解决

《C++右移运算符的一个小坑及解决》文章指出右移运算符处理负数时左侧补1导致死循环,与除法行为不同,强调需注意补码机制以正确统计二进制1的个数... 目录我遇到了这么一个www.chinasem.cn函数由此可以看到也很好理解总结我遇到了这么一个函数template<typename T>unsigned

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

C++ STL-string类底层实现过程

《C++STL-string类底层实现过程》本文实现了一个简易的string类,涵盖动态数组存储、深拷贝机制、迭代器支持、容量调整、字符串修改、运算符重载等功能,模拟标准string核心特性,重点强... 目录实现框架一、默认成员函数1.默认构造函数2.构造函数3.拷贝构造函数(重点)4.赋值运算符重载函数

C++ vector越界问题的完整解决方案

《C++vector越界问题的完整解决方案》在C++开发中,std::vector作为最常用的动态数组容器,其便捷性与性能优势使其成为处理可变长度数据的首选,然而,数组越界访问始终是威胁程序稳定性的... 目录引言一、vector越界的底层原理与危害1.1 越界访问的本质原因1.2 越界访问的实际危害二、基

c++日志库log4cplus快速入门小结

《c++日志库log4cplus快速入门小结》文章浏览阅读1.1w次,点赞9次,收藏44次。本文介绍Log4cplus,一种适用于C++的线程安全日志记录API,提供灵活的日志管理和配置控制。文章涵盖... 目录简介日志等级配置文件使用关于初始化使用示例总结参考资料简介log4j 用于Java,log4c

C++归并排序代码实现示例代码

《C++归并排序代码实现示例代码》归并排序将待排序数组分成两个子数组,分别对这两个子数组进行排序,然后将排序好的子数组合并,得到排序后的数组,:本文主要介绍C++归并排序代码实现的相关资料,需要的... 目录1 算法核心思想2 代码实现3 算法时间复杂度1 算法核心思想归并排序是一种高效的排序方式,需要用

C++11范围for初始化列表auto decltype详解

《C++11范围for初始化列表autodecltype详解》C++11引入auto类型推导、decltype类型推断、统一列表初始化、范围for循环及智能指针,提升代码简洁性、类型安全与资源管理效... 目录C++11新特性1. 自动类型推导auto1.1 基本语法2. decltype3. 列表初始化3

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

C++中detach的作用、使用场景及注意事项

《C++中detach的作用、使用场景及注意事项》关于C++中的detach,它主要涉及多线程编程中的线程管理,理解detach的作用、使用场景以及注意事项,对于写出高效、安全的多线程程序至关重要,下... 目录一、什么是join()?它的作用是什么?类比一下:二、join()的作用总结三、join()怎么