670

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

*.hpp使用over有什么优点和缺点*.h

4

20 回答 20

648

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

  • 自动代码格式化,对于格式化 C 和 C++ 代码,您可能有不同的准则。如果标题由扩展名分隔,您可以将编辑器设置为自动应用适当的格式
  • 命名,我一直在项目中使用 C 编写库,然后用 C++ 实现包装器。由于标头通常具有相似的名称,即 Feature.h 与 Feature.hpp,因此它们很容易区分。
  • 包含,也许您的项目有更合适的可用 C++ 编写的版本,但您使用的是 C 版本(见上文)。如果标头以实现它们的语言命名,您可以轻松发现所有 C 标头并检查 C++ 版本。

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

于 2008-09-30T11:41:07.437 回答
292

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

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

.hpp:C++ 头文件

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

此标头仅适用于 C++。

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

.h : C/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

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

例如:

#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
于 2008-09-30T18:57:25.110 回答
59

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

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

于 2008-09-30T14:28:14.073 回答
45

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

*.h用于 C 和*.hppC++。

于 2008-09-30T10:48:26.580 回答
36

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

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

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

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

引用自 Boost FAQ,

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

于 2013-12-03T12:08:15.700 回答
19

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


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

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

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

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

所以我们开始吧。

C++文档(我实际上是从 N3690 版本中引用的)定义标头必须符合以下语法:

2.9 标题名称

header-name:
    < h-char-sequence >
    " q-char-sequence "
h-char-sequence:
    h-char
    h-char-sequence h-char
h-char:
    any member of the source character set except new-line and >
q-char-sequence:
    q-char
    q-char-sequence q-char
q-char:
    any member of the source character set except new-line and "

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

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

#include "prettyStupidIdea.>"

将是有效的,但是:

#include <prettyStupidIdea.>>

将是无效的。反之亦然。

乃至

#include <<.<>

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

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

.hpp也是有效的原因。

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

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

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

但它不是语言的一部分。

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

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

结论:

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

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

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


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

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

于 2016-03-08T13:14:45.330 回答
17

我最近开始使用*.hppc++ 标头。

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

除了这个事实,我认为没有充分的理由选择*.h*.hpp反之亦然。

于 2008-09-30T11:28:46.390 回答
9

你可以随意调用你的includes。

只需要在#include.

我建议如果您使用 C 来使用.h,以及何时使用 C++ 来使用.hpp.

这最终只是一个约定。

于 2008-09-30T10:51:38.803 回答
8

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

于 2008-09-30T14:15:28.737 回答
7

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

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

于 2008-09-30T15:18:51.923 回答
6

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

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

于 2008-09-30T10:53:02.497 回答
6

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。

于 2017-08-13T08:32:01.057 回答
5

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

于 2008-09-30T11:15:49.167 回答
5

幸运的是,这很简单。

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

于 2017-09-05T11:51:14.640 回答
4

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

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

于 2017-08-18T23:42:42.287 回答
3

工具和人类很容易区分某些东西。就是这样。

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

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

  • 它不受语言规范的强制,无论是 C 还是 C++。存在许多不遵循惯例的项目。一旦你需要合并(混合)它们,就会很麻烦。
  • .hpp本身并不是唯一的选择。为什么不呢.hh.hxx(尽管如此,您通常至少需要一个关于文件名和路径的常规规则。)

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

  • 项目的每个部分使用的语言都有明确的记录。没有机会在同一个模块(目录)中混合 C 和 C++。每个 3rdparty 库都必须遵守此规则。
  • 项目使用的符合语言规范和允许的语言方言也被记录在案。(事实上​​,我什至记录了正在使用的标准功能和错误修复(在语言标准上)的来源。)这比区分使用的语言更重要,因为它太容易出错并且测试成本很高(例如编译器兼容性)可能很重要(复杂且耗时),尤其是在已经使用几乎纯C++ 的项目中。文件名太弱而无法处理。
  • 即使对于相同的 C++ 方言,也可能有更重要的属性适合差异。例如,请参阅下面的约定。
  • 文件名本质上是脆弱的元数据。违反惯例并不那么容易被发现。为了稳定地处理内容,工具最终不应仅依赖于名称。扩展之间的区别只是一个提示。也不应该期望使用它的工具始终表现相同,例如.hgithub.com 上文件的语言检测。(在shebang之类的评论中可能有一些东西让这些源文件成为更好的元数据,但它甚至不像文件名那样传统,因此通常也不可靠。)

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

于 2016-01-30T01:20:33.563 回答
2

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

于 2008-09-30T14:26:16.930 回答
2

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

但是,*.hpp 也可以!

于 2013-05-29T16:25:41.343 回答
2

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

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

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

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

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

于 2016-06-15T03:50:46.663 回答
1

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

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

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

于 2008-09-30T11:34:42.273 回答