你写过没有保护的标题吗?

发布于 2024-12-09 18:52:40 字数 253 浏览 0 评论 0原文

我想知道为什么 C++ 编译器不自动为标头生成标头防护?

// Why do I have to write this for every .hpp file I create?!!
#ifndef myheader_hpp__
#define myheader_hpp__
// ...
#endif

我还没有遇到过在编写标题时不需要它们的情况。我看不到相反行为的真实用例,但我很高兴看到一个。是有技术困难还是只是历史?!

I am wondering why C++ compilers don't generate header guards automatically for headers?

// Why do I have to write this for every .hpp file I create?!!
#ifndef myheader_hpp__
#define myheader_hpp__
// ...
#endif

I haven't met a situation where they aren't needed when I write my headers. I can't see a real use-case of the opposite behavior, but I would be glad to see one. Is there a technical difficulty or is it just history?!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

九厘米的零° 2024-12-16 18:52:40

一些预处理器技巧,需要将相同的标头多次包含到同一编译单元中< /a>. 另一个参考。

除此之外,大多数编译器确实允许您将所有内容缩短为:

#pragma once

There are some preprocessor tricks that require the same header included multiple times into the same compilation unit. Another reference.

Besides that, most compilers do allow you to shorten all of that down to:

#pragma once
芸娘子的小脾气 2024-12-16 18:52:40

对于编译器来说,自动放入包含防护并不真正实用。您可以定义方法/函数/类/等的原型而不会遇到问题,这通常是在标头中完成的。但是,当在标头中定义类时,如果该类被两个不同的 .cpp 文件或其他标头包含,您会遇到编译器多次定义该类的问题。

实际上,包含守卫只是标头的一种技巧。您并不总是需要它们,并且在某些情况下您不会使用它们。不管你信不信,这实际上更容易。

To a compiler, automatically putting in include guards isn't truly practical. You can define prototypes for methods/functions/classes/etc without running into problems, and this is usually done in a header. When a class is defined in a header, though, you run into the problem of having the class defined more than once by the compiler if it is included by two different .cpp files or other headers.

Really, include guards are just one trick for headers. You don't always need them, and there are some cases where you wouldn't use them. This is actually easier, believe it or not.

丿*梦醉红颜 2024-12-16 18:52:40

因为它是一种将一个文件插入另一个文件的通用机制。

只是在 99% 的情况下,通用目的能力都用于非常常见的特定目的。

Because it's a general purpose mechanism to insert one file into another.

It's just that general purpose ability is used for a very common specific purpose in 99% of the cases.

合久必婚 2024-12-16 18:52:40

我将简单地向您介绍 Clang / LLVM 项目。

在这个项目中,他们创建了一种使用简单的描述性语言对数据进行编码的方法,然后将其提供给旨在生成 C++ 文件的工具(称为表生成器的 tblgen)。例如,诊断

let Component = "Sema" in {
let CategoryName = "Semantic Issue" in {

// Constant expressions
def err_expr_not_ice : Error<
  "expression is not an integer constant expression">;

....

: Clang 中有数千个诊断信息,分为几个文件。一旦被 tblgen 处理,它们将生成一个巨大的 .inc 文件,对于每个诊断,该文件将包含一个宏调用。通过定义宏并包含该文件,您可以生成 C++ 表(或者其他任何东西,但通常用于表):

static const StaticDiagInfoRec StaticDiagInfo[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,               \
             SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,              \
             CATEGORY,BRIEF,FULL)                                 \
  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS,           \
    NOWERROR, SHOWINSYSHEADER, CATEGORY,                          \
    STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t),           \
    STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t),          \
    STR_SIZE(FULL, uint16_t),                                     \
    #ENUM, GROUP, DESC, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

相同的文件可以生成不同的表,因为您可以根据需要自由编写宏。

当然,这是一个非常具体的用途。

但不用担心,即使这些模块没有进入 C++11,我们也可以期待 C++1x。

I'll simply point you to the Clang / LLVM project.

In this project, they created a way to encode data using a simple descriptive language, that is then fed up to a tool (called tblgen for Table Generator) that is meant to produce a C++ file. For example, the diagnostics:

let Component = "Sema" in {
let CategoryName = "Semantic Issue" in {

// Constant expressions
def err_expr_not_ice : Error<
  "expression is not an integer constant expression">;

....

There are a few thousands diagnostics in Clang, separated in several files. Once processed by tblgen, they will generate a huge .inc file which, for each diagnostic, will contain a macro call. By defining the macro and including the file, you can produce a C++ table (or anything else really, but the use is generally for tables):

static const StaticDiagInfoRec StaticDiagInfo[] = {
#define DIAG(ENUM,CLASS,DEFAULT_MAPPING,DESC,GROUP,               \
             SFINAE,ACCESS,NOWERROR,SHOWINSYSHEADER,              \
             CATEGORY,BRIEF,FULL)                                 \
  { diag::ENUM, DEFAULT_MAPPING, CLASS, SFINAE, ACCESS,           \
    NOWERROR, SHOWINSYSHEADER, CATEGORY,                          \
    STR_SIZE(#ENUM, uint8_t), STR_SIZE(GROUP, uint8_t),           \
    STR_SIZE(DESC, uint16_t), STR_SIZE(BRIEF, uint16_t),          \
    STR_SIZE(FULL, uint16_t),                                     \
    #ENUM, GROUP, DESC, BRIEF, FULL },
#include "clang/Basic/DiagnosticCommonKinds.inc"
#include "clang/Basic/DiagnosticDriverKinds.inc"
#include "clang/Basic/DiagnosticFrontendKinds.inc"
#include "clang/Basic/DiagnosticLexKinds.inc"
#include "clang/Basic/DiagnosticParseKinds.inc"
#include "clang/Basic/DiagnosticASTKinds.inc"
#include "clang/Basic/DiagnosticSemaKinds.inc"
#include "clang/Basic/DiagnosticAnalysisKinds.inc"
#undef DIAG
  { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
};

And the same files can produce different tables, since you are free to write the macros as you wish.

It is, of course, a very specific use.

But don't worry, even though the modules didn't make it into C++11, we can hope for C++1x.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文