如果我在文件中包含iostream
或任何其他头文件两次会怎样?
我知道编译器不会抛出错误。
代码会被添加两次还是内部会发生什么?
当我们包含头文件时会发生什么?
答案 0 :(得分:14)
Include guard可防止编译器实际看到文件内容两次。
包含保护基本上是一组预处理器的条件指令,位于头文件的开头和结尾:
#ifndef SOME_STRING_H
#define SOME_STRING_H
//...
#endif
现在,如果您将文件包含两次,则第一次定义宏SOME_STRING_H
未定义,因此编译器会处理并查看文件的内容。但是,由于#ifdef
之后的第一件事是#define
,因此SOME_STRING_H
被定义,下一次编译器看不到头文件的内容。
为避免冲突,包含保护中使用的宏的名称取决于头文件的名称。
答案 1 :(得分:3)
头文件是简单的野兽。当您#include <header>
发生的所有事情都是header
的内容基本上被复制粘贴到文件中。要阻止多次包含标头,会使用include guards
,这就是为什么在大多数标头文件中您会看到类似于
#ifndef SOME_HEADER_FILE_GUARD
#define SOME_HEADER_FILE_GUARD
//Contents of Header
#endif
答案 2 :(得分:2)
由于以下几行的预处理程序代码,它只是被跳过:
#ifndef MY_HEADER_H
#define MY_HEADER_H
<actual header code here>
#endif
因此,如果您包含两次,则MY_HEADER_H
已经定义,并且预处理器会跳过#ifndef
和#endif
之间的所有内容。
答案 3 :(得分:1)
这取决于。除<assert>
外,该标准要求使用
第二个(以及后面)包括一个标准的标题作为无操作。这是
然而,标题的特征;编译器将(至少
概念上)每次读取并包含所有标题文本
遇到包括。
在这种情况下避免多重定义的标准做法是 使用include guard:标题中的所有C ++代码都是 包含在以下内容中:
#ifndef SPECIAL_NAME
#define SPECIAL_NAME
// All of the C++ code here
#endif SPECIAL_NAME
显然,每个标题都需要不同的名称。在一个应用程序中
你通常可以根据文件名建立约定
地点;像subsystem_filename
这样的东西
C ++符号中不合法的字符(如果你在你的中使用它们)
映射的文件名(通常是大写的)。对于
图书馆,最佳做法是产生相当长的时间
随机字符序列;更频繁(虽然肯定
从执行质量的角度来看,是低于确保的
每个这样的符号都以记录的前缀开头。
系统库当然可以使用保留符号(例如符号)
以下划线后跟大写字母开头)
保证没有冲突。或者它可以完全使用一些
不同的,依赖于实现的技术例如,微软,
使用编译器扩展#pragma once
; g ++使用包括守卫
始终以_GLIBCXX
开头(这不是用户代码中的合法符号)。
您无需使用这些选项。
答案 4 :(得分:0)
包括头文件时,其所有内容都将复制到放置“ #include”伪指令的行中。这是由预处理程序完成的,是编译过程中的一个步骤。
对于标准文件(例如iostream或存储在本地目录中的用户制作的“ .h”文件),此过程相同。但是,语法略有不同。
对于存储在库中的“ iostream”之类的文件,我们使用#include <filename>
。而对于本地目录中的头文件,我们使用#include "filename.h"
。
现在,如果我们两次包含头文件怎么办:
理想情况下,应将内容复制两次。但是...
许多头文件使用现代#pragma once
提法,即指示预处理器仅复制一次内容,无论头文件包含多少次。
一些非常古老的代码使用了一个名为“ include gaurds”的概念。我不会解释,因为其他答案都做得很好。
使用pragma once
是一种简便且现代的方法,但是,包含防护措施在以前已经被广泛使用,并且是解决此问题的相对复杂的方法。