有 C++ 标准库 ifdef 或 ifndef 预处理器指令吗?

Posted

技术标签:

【中文标题】有 C++ 标准库 ifdef 或 ifndef 预处理器指令吗?【英文标题】:Have C++ standard library ifdef or ifndef preprocessor instructions? 【发布时间】:2019-01-20 12:39:18 【问题描述】:

我正在用 C++ 构建自己的终端应用程序项目,并且我在问自己标准库是否有 ifdef 或 ifndef 预处理器指令。我想知道,因为我需要创建不同的头文件,这些头文件需要一些标准库头文件,例如“字符串”和其他一些头文件,所以我不想包含同一个库 3 次或更多次,因为它会使程序更重。 例如,我在头文件上写了这样的内容,以防止 .h 文件被多次包含:

#ifndef myheader_h
#define myheader_h
    // my file code here
#endif

我尝试编译,但编译器对错误或警告只字未提。 我还尝试阅读标准库源代码 (https://en.cppreference.com/w/cpp/header),但没有找到任何预处理器规则,如 ifdef 或 ifndef。 我应该包含这样的标准库头文件吗?

#ifndef string_h
#define string_h
    #include <string>
#endif

我希望我的问题还没有被问到,因为我在搜索时没有找到它。

更新

对于那些说“你不在需要担心的位置”并且说“如果有适当的包含警卫,成本会很低”的人,我的意思是:程序的重量很重要,我想让它更轻,所以我不想多次完全包含同一个文件。标准库文件是否正确包含警卫? (我的头文件有,不知道std lib文件)

【问题讨论】:

您误解了包含警卫的工作方式。除了您正在编写的标题之外,您无需为任何标题考虑这一点。有关示例,请参见 en.wikipedia.org/wiki/Include_guard。 “我不想包含同一个库 3 次或更多次,因为它会使程序变得更重。” 听起来你并不完全处于你需要的位置一开始就担心你的程序很“重”(不管你怎么定义)。 &lt;string&gt; 已经包含相同(或相似)的构造。你不需要自己写另一个。 多次包含同一个标头的成本非常少(如“它可以忽略不计”),如果它具有适当的包含保护。 【参考方案1】:

对于#define 任何特定预处理器符号的标准头文件没有要求,以确保它们可以是#included 多次。

话虽如此,任何理智的实现都会确保它们可以多次#included 而不会对应用程序代码产生不利影响。

事实证明,这是大多数标头标准的要求(谢谢,@Rakete1111)。

来自C++ standard

翻译单元可以包含任何顺序的库头 ([lex])。每个都可以包含多次,与仅包含一次没有任何不同,除了包含&lt;cassert&gt;&lt;assert.h&gt; 的效果每次都取决于NDEBUG 的词汇当前定义。

不仅如此,他们很可能会使用#pragma once 指令。因此,即使您对同一个标头多次使用#include,它们也只会被读取一次。

总之,不用担心标准头文件。如果你的头文件实现正确,你的应用程序就可以了。

【讨论】:

“每个都可以被包含多次,与只包含一次没有任何不同,[...]”。所以已经要求使用某种标头保护 (eel.is/c++draft/using.headers#2)【参考方案2】:

我在问自己 [原文如此] 标准库是否有 ifdef 或 ifndef 预处理器指令

该标准没有指定是否有ifdef 样式的标头保护,尽管它确实要求以某种方式保护多重包含。我看了一下 stdlibc++ 标准库实现的随机头文件。它确实有标题保护。

我不想将同一个库包含 3 次或更多次,因为这会使程序变得更重

多次包含头文件并不会使程序“更重”。

我应该包含这样的标准库头文件吗?

#ifndef string_h
#define string_h
    #include <string>
#endif

这不是必需的,或者特别有用。

【讨论】:

【参考方案3】:

您正在谈论的那些预处理器指令称为“头文件保护”,标准库头文件肯定具有它们(或执行相同操作的其他机制),就像所有其他适当的头文件一样。多次包含它们应该不会导致任何问题,您只需要在编写自己的头文件时担心这些。

您正在阅读的“源代码”只是说明头文件应如何工作的文档,但它不提供实际代码。要查看代码,您可以查看编译器提供的头文件。例如,Visual Studio 中的 &lt;iostream&gt; 标头同时具有 #pragma once 和标头保护:

#pragma once
#ifndef _IOSTREAM_
#define _IOSTREAM_
//...
#endif /* _IOSTREAM_ */

GCC 编译器提供的头文件也有头文件保护:

#ifndef _GLIBCXX_IOSTREAM
#define _GLIBCXX_IOSTREAM 1
//...
#endif /* _GLIBCXX_IOSTREAM */

【讨论】:

以上是关于有 C++ 标准库 ifdef 或 ifndef 预处理器指令吗?的主要内容,如果未能解决你的问题,请参考以下文章

C++中#if #ifdef 的作用

#ifdef 和 #ifndef 的作用

C++中 #ifdef的妙用详解

makefile中ifeq,ifneq,ifdef和ifndef的区别与用法

C语言与C++常见面试题

makefile中ifeq,ifneq,ifdef和ifndef的区别与用法