简体   繁体   English

为什么需要包含C ++头文件的保护?

[英]Why do you need inclusion guard for C++ header files?

I get roughly what it does. 我粗略地了解它的作用。 What I don't understand is why it's not the default? 我不明白为什么它不是默认值? What are the use cases where some header file would need to be included multiple times? 有些头文件需要多次包含的用例有哪些?

The reason it's not the default is primarily historical these days -- when the C language was formalized, #include was specified that it must act exactly as if the user had copy-and-pasted the specified file's contents at the location of the #include -line; 它不是默认的原因主要是历史 - 当C语言被形式化时, #include被指定它必须完全像用户在#include的位置复制并粘贴指定文件的内容一样-线; and C++ wanted (and wants) to remain as compatible as possible with C, so C++ inherited that behavior from C. 和C ++希望(并希望)保持与C尽可能兼容,因此C ++从C继承了这种行为。

As for a use-case where including the same header file more than once might be useful; 对于多次包含相同头文件的用例可能是有用的; one instance where I found it useful was for simulating a templated-container-class in C (because C doesn't support templates directly). 我发现它有用的一个实例是在C中模拟模板化容器类(因为C不直接支持模板)。 I had a container-implementation-header-file that looked something like this (but more elaborate; I'm showing a simplified version here for readability): 我有一个容器实现头文件看起来像这样(但更详细;我在这里显示简化版本的可读性):

// MyContainerImplemention.h
// be sure to #define MYTYPE and MYARRAYSIZE
// before #include-ing this file!

struct ArrayOf##MYTYPE
{
   MYTYPE arrayOfItems[MYARRAYSIZE];
};

inline void Set##MYTYPE##Item(struct ArrayOf##MyType * container, int which, MYTYPE item) 
{
   container[which] = item;
}

[... and so on for various other MYTYPE-specific methods ...]

... then my .c files could do something like: ...然后我的.c文件可以做类似的事情:

#define MYTYPE int
#define MYARRAYSIZE 10
#include "MyContainerImplementation.h"
#undef MYARRAYSIZE
#undef MYTYPE

#define MYTYPE short
#define MYARRAYSIZE 15
#include "MyContainerImplementation.h"
#undef MYARRAYSIZE
#undef MYTYPE

struct ArrayOfint myInts;
struct ArrayOfshort myShorts;

SetintItem(&myInts, 5, 12);
SetshortItem(&myShorts, 3, 2);
[...]

... and end up with the container "class" and its associated methods implemented for each data-type, without having to manually write a new implementation of the container "class" each time. ...最终得到容器“class”及其为每种数据类型实现的相关方法,而不必每次都手动编写容器“class”的新实现。

Yes, it was extremely ugly -- but not as ugly as having to manually write out thousands of lines of redundant container-code would have been. 是的,它非常难看 - 但不像手动写出数千行冗余容器代码一样难看。 (The real container-implementation-header-file implemented a hash table and was several hundred lines long) (真正的container-implementation-header-file实现了一个哈希表,并且有几百行)

Without include guards or #pragma once the compiler would have to maintain a list of included files. 一旦编译器必须维护包含文件的列表,就不使用包含保护或#pragma。 This is not easy, because of different possible paths to these files (and #pragma once doesn't completely solve this) and would be expecting a bit much of the original C compilers, which had to work with very limited memory. 这并不容易,因为这些文件有不同的可能路径(而#pragma曾经没有完全解决这个问题),并且期待原始C编译器的大部分,它必须使用非常有限的内存。

What's true today is not necessarily true when C came about and the C pre-processor, upon which the C++ one is based, was created. 今天的情况并非如此,当C出现时,C ++的基础上创建了C预处理器。

#pragma once is just a step towards having proper C++ modules so this annoying historical legacy is finally eliminated. #pragma once只是迈向正确的C ++模块的一步,因此最终消除了这个烦人的历史遗产。

Yes, it's valid to include a file multiple times, and yes, each time it's included it can behave in entirely different ways. 是的,多次包含文件是有效的,是的,每次包含文件时,它都可以以完全不同的方式运行。 This is why making pre-compiled headers is a huge headache for compiler developers. 这就是为什么编译预编译头文件对编译器开发人员来说是一个巨大的麻烦

Guard blocks or #pragma once are included in order to prevent a file from being included multiple times. 包含Guard块或#pragma once ,以防止多次包含文件。

#pragma once , while supported on most compilers, is not an official part of the c++ standard, and may not work on every compiler. #pragma once虽然在大多数编译器上都受支持,但它不是c ++标准的官方部分,并且可能不适用于每个编译器。 You can use a guard block, which will work on any compiler. 您可以使用保护块,它可以在任何编译器上运行。 An example of a guard block in the file MyClass.hpp would be: MyClass.hpp文件中的保护块示例如下:

#ifndef MYCLASS_HPP
#define MYCLASS_HPP

//Code here

#endif

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM