ChatGPT解决这个技术问题 Extra ChatGPT

*.h 或 *.hpp 用于您的类定义

我一直为我的类定义使用 *.h 文件,但在阅读了一些 boost 库代码后,我意识到它们都使用 *.hpp。我一直讨厌那个文件扩展名,我想主要是因为我不习惯它。

使用 *.hpp 而不是 *.h 的优点和缺点是什么?

同时有 The C++ Core Guidelines 明确推荐 *.h

D
David Holm

以下是对 C 和 C++ 头文件进行不同命名的几个原因:

自动代码格式化,对于格式化 C 和 C++ 代码,您可能有不同的准则。如果标题由扩展名分隔,您可以将编辑器设置为自动应用适当的格式

命名,我一直在项目中使用 C 编写库,然后用 C++ 实现包装器。由于标头通常具有相似的名称,即 Feature.h 与 Feature.hpp,因此它们很容易区分。

包含,也许您的项目有更合适的可用 C++ 编写的版本,但您使用的是 C 版本(见上文)。如果标头以实现它们的语言命名,您可以轻松发现所有 C 标头并检查 C++ 版本。

请记住,C 不是 C++,除非您知道自己在做什么,否则混合搭配可能非常危险。适当地命名您的来源可以帮助您区分语言。


C
Community

我使用 .hpp 是因为我希望用户区分哪些标头是 C++ 标头,哪些标头是 C 标头。

当您的项目同时使用 C 和 C++ 模块时,这可能很重要:就像我之前解释的其他人一样,您应该非常小心地执行此操作,并且它从您通过扩展提供的“合同”开始

.hpp:C++ 头文件

(或.hxx,或.hh,或其他)

此标头仅适用于 C++。

如果您在 C 模块中,甚至不要尝试包含它。你不会喜欢它,因为没有做任何努力使它对 C 友好(会丢失太多,比如函数重载、命名空间等)。

.h : C/C++ 兼容或纯 C 头文件

源代码和 C++ 源代码都可以直接或间接地包含此标头。

它可以直接包含,受 __cplusplus 宏保护:

这意味着,从 C++ 的角度来看,与 C 兼容的代码将被定义为 extern "C"。

从 C 的角度来看,所有 C 代码都将清晰可见,但 C++ 代码将被隐藏(因为它不会在 C 编译器中编译)。

例如:

#ifndef MY_HEADER_H
#define MY_HEADER_H

   #ifdef __cplusplus
      extern "C"
      {
   #endif

   void myCFunction() ;

   #ifdef __cplusplus
      } // extern "C"
   #endif

#endif // MY_HEADER_H

或者它可以通过相应的 .hpp 标头间接包含在 extern "C" 声明中。

例如:

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP

extern "C"
{
#include "my_header.h"
}

#endif // MY_HEADER_HPP

和:

#ifndef MY_HEADER_H
#define MY_HEADER_H

void myCFunction() ;

#endif // MY_HEADER_H

这在许多 C++ 项目中是非常不习惯的。 .h 文件用于非常非 C'ish 的东西。
@einpoklum:当然。但我尽量避免“猴子看猴子做”的行为。在当前情况下,两个扩展(和其他扩展)都可用,所以我尝试让它们实际计数。与客户共享代码的合同非常有用:每个人(即数百名开发人员)都知道“.H”文件将由使用 C 编译器的客户使用,因此没有错误可以去那里或不是。每个人(包括客户)都知道“.HPP”文件永远不会尝试对 C 语言友好。每个人都赢了。
@paercebal,所以您建议使用 .H 而不是 .h,以及 .HPP 而不是 .hpp?
@GeofSawaya:不,抱歉。这是一种习惯。在撰写文章时,我使用大写的扩展名来区分文件的类型,例如“.HPP 文件”。但是我硬盘上实际文件的扩展名总是小写的,即使名称不是,比如“MyClass.hpp”或“module.hpp”
谢谢,@paercebal。我变得迂腐了
m
mtb

我一直认为 .hpp 标头是 .h.cpp 文件的一种组合...一个包含实现细节的标头。

通常,当我看到(并使用).hpp 作为扩展名时,没有相应的 .cpp 文件。正如其他人所说,这不是一个硬性规定,只是我倾向于使用 .hpp 文件的方式。


m
mtb

您使用哪个扩展并不重要。任何一个都可以。

我对 C 使用 *.h,对 C++ 使用 *.hpp


C
Community

编辑 [添加来自 Dan Nissenbaum 的建议]:

按照一种约定,当原型在标头本身中定义时使用 .hpp 文件。头文件中的此类定义在模板的情况下很有用,因为编译器仅在模板实例化时为每种类型生成代码。因此,如果它们没有在头文件中定义,它们的定义将不会在链接时从其他编译单元解析。如果您的项目是一个大量使用模板的纯 C++ 项目,则此约定将很有用。

某些遵循此约定的模板库提供带有 .hpp 扩展名的标头,以表明它们没有相应的 .cpp 文件。

另一个约定是使用 .h 表示 C 头文件,使用 .hpp 表示 C++;一个很好的例子是 boost 库。

引用 Boost FAQ,文件扩展名将文件的“类型”传达给人类和计算机程序。 '.h' 扩展名用于 C 头文件,因此传达了有关 C++ 头文件的错误信息。不使用扩展名不会传达任何信息并强制检查文件内容以确定类型。使用 '.hpp' 明确地将其标识为 C++ 头文件,并且在实际实践中运行良好。 (雷纳·戴克)


这些都不是真的,在代码生成或链接方面,文件是 .h 还是 .hpp 没有区别。
这不只是惯例问题吗? C++ 标准库提供了它的所有头文件,没有任何扩展。使用“.hpp”只是表示原型是在同一个文件中定义的,不会有任何对应的.cpp文件。
我认为这个答案很有用,除了它缺少一个非常简单但重要的短语:“按照惯例,而不是按照语言规则”(某处)。
P
Pang

我正在回答这个作为提醒,以指出我对“user1949346”对同一OP的回答的评论。

正如许多人已经回答的那样:任何一种方式都可以。其次是强调自己的印象。

介绍性的,正如前面提到的评论所述,我的意见是如果实际上没有理由反对,C++ 标头扩展被提议为 .h

由于 ISO/IEC 文档使用这种头文件表示法,因此在他们关于 C++ 的语言文档中甚至没有出现与 .hpp 匹配的字符串。

但我现在的目标是有一个可以接受的理由,为什么任何一种方式都可以,尤其是为什么它不是它自己的语言的主题。

所以我们开始吧。

C++ 文档(我实际上是参考 N3690 版本)定义标头必须符合以下语法:

2.9 标题名称 header-name: < h-char-sequence > " q-char-sequence " h-char-sequence: h-char h-char-sequence h-char h-char: 源字符集的任何成员,除了new-line and > q-char-sequence: q-char q-char-sequence q-char q-char: 源字符集的任何成员,除了 new-line 和 "

因此,正如我们可以从这部分中提取的那样,头文件名也可以是源代码中有效的任何内容。除了包含 '\n' 字符并且取决于它是否包含在 <> 中之外,它不允许包含 >。或者如果它被 ""-include 包含,则不允许包含 "

换句话说:如果您有一个支持像 prettyStupidIdea.> 这样的文件名的环境,则包含如下:

#include "prettyStupidIdea.>"

将是有效的,但是:

#include <prettyStupidIdea.>>

将是无效的。反之亦然。

乃至

#include <<.<>

将是一个有效的可包含头文件名。

即使这符合C++,这也是一个非常愚蠢的想法。

这也是 .hpp 有效的原因。

但这不是委员会为语言设计决策的结果!

因此,讨论即将使用 .hpp 与讨论 .cc.mm 或我在其他有关该主题的帖子中读到的其他内容相同。

我不得不承认我不知道 .hpp 来自哪里1,但我敢打赌,某个解析工具、IDE 或其他与 C++ 相关的东西的发明者会想到这个想法来优化一些内部流程或只是为了发明一些(甚至可能对他们来说是必要的)新的命名约定。

但它不是语言的一部分。

每当人们决定以这种方式使用它时。可能是因为他最喜欢它,或者因为工作流的某些应用程序需要它,它从来不是语言的要求。因此,无论谁说“pp 是因为它与 C++ 一起使用”,在语言定义方面都是错误的。

C++ 允许任何尊重上一段的内容。如果委员会建议使用任何东西,那么它使用的是 .h,因为这是 ISO 文档的所有示例中都被起诉的扩展名。

结论:

只要您看不到/觉得不需要使用 .h 而不是 .hpp 或反之亦然,您就不必费心了。因为两者都将形成相对于标准具有相同质量的有效标题名称。因此,要求您使用 .h.hpp 的任何内容都是对标准的附加限制,甚至可能与其他不符合的附加限制相矛盾。但由于 OP 没有提到任何额外的语言限制,这是对该问题的唯一正确和可认可的答案

“您的类定义的 *.h 或 *.hpp”是:

只要不存在外部限制,两者都同样正确和适用。

1据我所知,显然是 boost 框架提出了那个 .hpp 扩展。

2当然我不能说一些未来的版本会带来什么!


m
mtb

我最近开始将 *.hpp 用于 c++ 标头。

原因是我使用 emacs 作为我的主要编辑器,当你加载 *.h 文件时它会自动进入 c 模式,当你加载 *.hpp 文件时它会自动进入 c++ 模式。

除此之外,我认为没有充分的理由选择 *.h 而不是 *.hpp,反之亦然。


就个人而言,我认为 C++ 突出显示即使在 C 标头中也是一个好主意。我一直处于有人想要从 C++ 中包含 C 标头的情况的两端,但它使用 C++ 关键字作为参数名称......
m
mtb

你可以随意调用你的includes。

只需在 #include 中指定该全名。

我建议如果您使用 C 使用 .h,而使用 C++ 时使用 .hpp

这最终只是一个约定。


J
JohnMcG

我更喜欢 C++ 的 .hpp,以便让编辑和其他程序员都清楚它是 C++ 头文件而不是 C 头文件。


R
Roddy

Codegear C++Builder 将 .hpp 用于从 Delphi 源文件自动生成的头文件,并将 .h 文件用于“自己的”头文件。

因此,当我编写 C++ 头文件时,我总是使用 .h。


D
Dynite

C++(“C Plus Plus”)作为 .cpp 是有意义的

具有 .hpp 扩展名的头文件没有相同的逻辑流程。


C
Community

Bjarne Stroustrup 和 Herb Sutter 在他们的 C++ 核心指南中对这个问题有一个声明:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#S-source 这也指标准扩展(C++11、C++14 等)的最新变化

SF.1:如果您的 Y 项目尚未遵循其他约定,则对代码文件使用 .cpp 后缀,对接口文件使用 .h 后缀 原因 这是一个长期的约定。但是一致性更重要,所以如果您的项目使用其他东西,请遵循它。注意 此约定反映了一种常见的使用模式:标头更常与 C 共享以编译为 C++ 和 C,通常使用 .h,并且更容易将所有标头命名为 .h,而不是仅对那些标头具有不同的扩展名旨在与 C 共享。另一方面,实现文件很少与 C 共享,因此通常应与 .c 文件区分开来,因此通常最好将所有 C++ 实现文件命名为其他名称(例如 .cpp)。特定名称 .h 和 .cpp 不是必需的(仅推荐作为默认名称),其他名称已广泛使用。例如 .hh、.C 和 .cxx。等效地使用这些名称。在本文档中,我们将 .h 和 .cpp > 称为头文件和实现文件的简写,即使实际扩展名可能不同。您的 IDE(如果您使用一个)可能对足够的意见有强烈的看法。

我不是这个约定的忠实拥护者,因为如果您使用像 boost 这样的流行库,那么您的一致性已经被打破,您应该更好地使用 .hpp。


N
Nykal

幸运的是,这很简单。

如果您使用 C++,您应该使用 .hpp 扩展名,并且您应该将 .h 用于 C 或混合使用 C 和 C++。


c
camh

在 90 年代初我的一项工作中,我们分别使用 .cc 和 .hh 作为源文件和头文件。我仍然更喜欢它而不是所有替代品,可能是因为它最容易打字。


E
Enzo

正如这里的许多人已经提到的,我也更喜欢将 .hpp 用于使用模板类/函数的仅标头库。我更喜欢将 .h 用于带有 .cpp 源文件或共享或静态库的头文件。

我开发的大多数库都是基于模板的,因此只需要头文件,但是在编写应用程序时,我倾向于将声明与实现分开,并以 .h 和 .cpp 文件结束


F
FrankHB

工具和人类很容易区分某些东西。而已。

在常规使用中(通过 boost 等),.hpp 是专门的 C++ 头文件。另一方面,.h 用于非 C++-only 标头(主要是 C)。精确检测内容的语言通常很困难,因为有很多不平凡的案例,因此这种差异通常使现成的工具易于编写。对人类来说,一旦得到约定,它也很容易记住和使用。

但是,我要指出,约定本身并不总是如预期的那样有效。

它不受语言规范的强制,无论是 C 还是 C++。存在许多不遵循惯例的项目。一旦你需要合并(混合)它们,就会很麻烦。

.hpp 本身并不是唯一的选择。为什么不是 .hh 或 .hxx? (尽管如此,您通常至少需要一个关于文件名和路径的常规规则。)

我个人在我的 C++ 项目中同时使用 .h.hpp。我不遵循上述约定,因为:

项目的每个部分使用的语言都有明确的记录。没有机会在同一个模块(目录)中混合 C 和 C++。每个 3rdparty 库都必须遵守此规则。

项目使用的符合语言规范和允许的语言方言也被记录在案。 (事实上,我什至记录了正在使用的标准功能和错误修复(在语言标准上)的来源。)这比区分使用的语言更重要,因为它太容易出错和测试成本(例如编译器兼容性)可能很重要(复杂且耗时),尤其是在已经使用几乎纯 C++ 的项目中。文件名太弱而无法处理。

即使对于相同的 C++ 方言,也可能有更重要的属性适合差异。例如,请参阅下面的约定。

文件名本质上是脆弱的元数据。违反惯例并不那么容易被发现。为了稳定地处理内容,工具最终不应仅依赖于名称。扩展之间的区别只是一个提示。也不应该期望使用它的工具始终表现相同,例如 github.com 上的 .h 文件的语言检测。 (在 shebang 之类的评论中可能有一些东西让这些源文件成为更好的元数据,但它甚至不像文件名那样传统,因此通常也不可靠。)

我通常在 C++ 标头上使用 .hpp,并且标头应该以 header-only 方式使用(维护),例如作为模板库。对于 .h 中的其他头文件,要么有相应的 .cpp 文件作为实现,要么是非 C++ 头文件。后者很容易通过人类(或通过具有显式嵌入元数据的工具,如果需要)来区分标头的内容。


M
Mark Ransom

我使用 .h 是因为这是 Microsoft 使用的,也是他们的代码生成器创建的。没有必要违背粮食。


并非无处不在,在很多示例(如 WINDDK)中,他们使用 .hpp
在谈到 C++ 时,我不会称微软为“谷物”。
@Brett 这是你的工作。即使不是,它也是一个非常流行的编译器。
@MarkRansom 我更多地指的是微软使用 C 的历史。IMO VC++ 是一个优秀的编译器。
@developerbmw 我会说 MSVC 是 Windows 程序的颗粒,而 GCC 是 *nix 程序的颗粒,就个人而言。据我所知,它们是这些平台的大多数其他编译器倾向于保持兼容的编译器。
佚名

在“The C++ Programming Language, Third Edition by Bjarne Stroustrup”,第一本 C++ 必读书籍,他使用 *.h。所以我认为最好的做法是使用 *.h。

但是,*.hpp 也可以!


如果有人写了一本关于他从其他人那里学到的东西的书,而其他人从另一本书(也许运气相同)那里学到了这本书,由可能有主要来源的人写的,那么这就是他们正在做的任何事情,而不是标记蜜蜂最佳实践。
顺便提一下:我实际上对此表示反对。但我会赞成它,如果它说“ISO/IEC N3690”或任何其他 C++ 草案而不是“Bjarne Stroustrup 的 C++ 编程语言第三版”。虽然这是一个有效的观点,因为语言本身根本没有提到 .hpp
@zaibis 你知道 Bjarne Stroustrup 发明了 C++ 对吗?
@tumtumtum:承认,我不知道这一点。但无论如何,即使在那种情况下,它仍然是委员会的文件,保持标准,这是可以参考的。即使他是语言的发明者,也不再是他的决定。因此,虽然这使这个答案更有价值,但它仍然不是一个有效的推理。
J
Justin Time - Reinstate Monica

任何特定扩展都没有任何优势,除了对您、编译器和/或您的工具可能有不同的含义。 header.h 是有效的标头。 header.hpp 是有效的标头。 header.hh 是有效的标头。 header.hx 是有效的标头。 h.header 是有效的标头。 this.is.not.a.valid.header 是拒绝的有效标头。 ihjkflajfajfklaf 是有效的标头。只要名称可以被编译器正确解析,并且文件系统支持它,它就是一个有效的标头,其扩展的唯一优势就是人们读入它的内容。

话虽如此,能够根据扩展名准确地做出假设是非常有用的,因此为您的头文件使用一组易于理解的规则是明智的。就个人而言,我更喜欢这样做:

如果已经有任何既定的指导方针,请遵循它们以防止混淆。如果项目中的所有源文件都使用相同的语言,请使用 .h。没有歧义。如果某些标头与多种语言兼容,而其他标头仅与一种语言兼容,则扩展基于标头兼容的最严格的语言。与 C 或同时与 C 和 C++ 兼容的标头会获得 .h,而与 C++ 但不兼容 C 的标头会获得 .hpp 或 .hh 或类似的东西。

当然,这只是处理扩展的许多方法之一,即使事情看起来很简单,你也不一定相信你的第一印象。例如,我看到有人提到将 .h 用于普通标头,将 .tpp 用于仅包含模板类成员函数定义的标头,其中 .h 文件定义模板类,其中 .tpp 文件定义它们的成员函数(而不是直接包含函数声明和定义的 .h 标头)。再举一个例子,很多人总是在其扩展中反映标题的语言,即使没有歧义的可能性。对他们来说,.h 始终是 C 标头,而 .hpp(或 .hh.hxx 等)始终是 C++ 标头。再一次,有些人使用 .h 表示“与源文件关联的标头”,使用 .hpp 表示“内联定义所有函数的标头”。

考虑到这一点,主要优势在于始终以相同的样式命名您的标题,并使该样式对任何检查您的代码的人都很明显。这样,任何熟悉您通常的编码风格的人都可以通过粗略的一瞥来确定您对任何给定扩展的含义。


M
Mike Dimmick

源文件的扩展名可能对您的构建系统有意义,例如,您的 makefile 中可能有一个用于 .cpp.c 文件的规则,或者您的编译器(例如 Microsoft cl.exe)可能会将文件编译为C 或 C++,取决于扩展名。

因为您必须为 #include 指令提供整个文件名,所以头文件扩展名是无关紧要的。如果愿意,您可以在另一个源文件中包含一个 .c 文件,因为它只是一个文本包含。您的编译器可能具有转储预处理输出的选项,这将使这一点变得清晰(Microsoft:/P 预处理到文件,/E 预处理到 stdout/EP 省略 #line 指令,/C保留评论)

您可以选择将 .hpp 用于仅与 C++ 环境相关的文件,即它们使用无法在 C 中编译的功能。