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


551

我一直在*.h类定义中使用文件,但是在阅读了一些boost库代码之后,我意识到它们都使用了*.hpp。我一直对该文件扩展名有所厌恶,主要是因为我不习惯使用该文件扩展名。

使用*.hppover有*.h什么优点和缺点?

Answers:


526

以下是C与C ++标头命名不同的几个原因:

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

记住,C 不是 C ++,除非您知道自己在做什么,否则混搭会非常危险。适当地命名源有助于您区分语言。


233

我使用.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

或者可以通过相应的.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

3
在许多C ++项目中,这是非常不习惯的。.h文件用于处理非常规的内容。
einpoklum '16

4
@einpoklum:当然可以。但是我尝试避免“猴子看见猴子做”的行为。在当前情况下,两个扩展名(和其他扩展名)都可用,因此我尝试使它们实际计数。与客户共享的代码具有这种约定非常有用:每个人(即成百上千的开发人员)都知道“ .H”文件将由使用C编译器的客户端使用,因此不会误解那里可以做什么或不。并且每个人(包括客户端)都知道“ .HPP”文件将永远不会成为C友好的。每个人都赢。
paercebal

4
@paercebal,所以您建议使用.H而不是.h,而建议使用.HPP而不是.hpp
Geof Sawaya

6
@GeofSawaya:不,对不起。这是一个习惯。撰写文章时,我使用大写扩展名按文件类型区分文件,例如“ .HPP文件”。但是,硬盘上实际文件的扩展名始终是小写字母,即使名称也不是,例如“ MyClass.hpp”或“ module.hpp”
paercebal

4
谢谢,@ paercebal。我上学了
Geof Sawaya

48

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

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


31

使用哪个扩展名都没有关系。两者都可以。

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


23

编辑 [添加了丹·尼森鲍姆的建议]:

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

某些遵守此约定的模板库提供了具有.hpp扩展名的标头,以指示它们没有相应的.cpp文件。

另一种约定是将.h用于C头文件,并将.hpp用于C ++;一个很好的例子是boost库。

引用Boost常见问题解答,

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


所有这些都不是正确的,就代码生成或链接而言,文件是.h还是.hpp都没有区别。
Mark Ingram 2013年

这不只是惯例问题吗?C ++ std库提供了所有标头,没有任何扩展名。使用“ .hpp”仅表示原型在同一文件中定义,并且将没有任何对应的.cpp文件。
ProgramCpp 2013年

5
我认为,这个答案很有用,但它缺少一个非常简单但很重要的短语:“按惯例,而不是按语言规则”(某处)。
Dan Nissenbaum 2014年

13

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

原因是我将emacs用作主编辑器,并且在加载*.h文件时它自动进入c模式,而在加载文件时它自动进入c ++模式*.hpp

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


7
我个人认为,即使在C标头中,C ++高亮也是一个好主意。我遇到过有人想从C ++包含C头的情况,但是它使用C ++关键字作为参数名称...
Steve Jessop

12

我在此提醒您,是为了指出我对同一OP的“ user1949346”答案的评论。


因此,正如许多已经回答的那样:两种方法都可以。其次是强调自己的印象。

引言,就像前面提到的命名注释中所述,我的意见是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或者我在该主题的其他帖子中看到的其他内容也是如此。

我不得不承认,我不知道哪里.hpp是从哪里来1,但我敢打赌,一些分析工具,IDE或别的什么关心的发明者C++来到这个想法,以优化一些内部流程,或者只是即使他们不一定发明一些(可能)的新命名约定。

但这不是语言的一部分。

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

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

结论:

只要您看不到/感觉不需要.h反复使用,.hpp反之亦然,您就不必打扰。因为两者都将构成一个相对于标准质量相同的有效标题名称。因此,任何需要您使用的内容.h.hpp对该标准的附加限制,甚至可能与其他彼此不一致的附加限制相抵触。但是由于OP没有提及任何其他语言限制,因此这是对该问题的唯一正确且可批准的答案

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

只要没有外部限制,两者都是正确的并且适用的。


1据我所知,显然是该.hpp扩展附带的boost框架。

2 当然,我不能说将来的某些版本会带来什么!


7

对于C ++,我更喜欢使用.hpp来使编辑者和其他程序员都清楚它是C ++头文件而不是C头文件。


6

C ++(“ C Plus Plus”)与.cpp一样有意义

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


6

您可以随心所欲地调用包含。

只需在中指定该全名即可#include

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

最后只是一个约定。


5

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

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


5

在90年代初我的一项工作中,我们分别将.cc和.hh用作源文件和头文件。我仍然比所有其他方法都更喜欢它,可能是因为它最容易输入。


5

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 ++实现文件命名为其他名称(例如.cpp)。

不需要特定的名称.h和.cpp(建议将其作为默认名称),其他名称也被广泛使用。示例是.hh,.C和.cxx。等效使用此类名称。在本文档中,即使实际扩展名可能不同,我们也将.h和.cpp>用作头文件和实现文件的简写。

您的IDE(如果使用的话)可能对满足要求有强烈的意见。

我不是这个约定的忠实拥护者,因为如果您使用的是诸如boost这样的流行库,则您的一致性已经被破坏,您最好使用.hpp。


4

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

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


3

幸运的是,它很简单。

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


2

我使用.h,因为这是Microsoft使用的,以及它们的代码生成器创建的内容。无需违反常规。


并非处处都是,在很多示例中(例如WINDDK),他们使用.hpp
marsh-wiggle

13
当涉及到C ++时,我不会称微软为“谷物”。
developerbmw

@Brett,这就是您的工作。即使不是,它还是一个流行的编译器。
2014年

@MarkRansom我更多是指Microsoft使用C的历史。IMO VC ++是出色的编译器。
developerbmw

1
@developerbmw我个人来说,MSVC是Windows程序的基础,而GCC是* nix程序的基础。据我所知,它们是那些平台上大多数其他编译器倾向于尝试保持兼容的程序。
贾斯汀时间-恢复莫妮卡

1

在必读的第1本书《 C ++编程语言,第三版,Bjarne Stroustrup》中,他使用* .h。因此,我认为最佳实践是使用* .h。

但是,*。hpp也可以!


1
如果有人写了一本关于他从其他人那里学到的东西的书,然后又从另一本(也许是运气好的话)书中学到了东西,那本书是由可能拥有主要资料来源的人写的,那么这就是他们在做什么,而不是在做什么。最佳实践。
dhein

只需提一下:我实际上做了这个。但是,如果它说“ ISO / IEC N3690”或“ Bjarne Stroustrup的第三版C ++编程语言”中的任何其他C ++草案,我都会赞成。尽管这是正确的一点,但由于.hpp语言本身完全没有提及。
dhein

9
@zaibis,您知道Bjarne Stroustrup发明了C ++吗?
tumtumtum

@tumtumtum:承认,我没有意识到这一点。但是无论如何,即使在那种情况下,它仍然是委员会的文件,保持了标准,这是值得参考的。即使他是语言的发明者,也不再是他的决定。因此,尽管这使该答案更有价值,但它仍然不是有效的推理。
dhein

1

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

在常规使用中(通过升压等),.hpp特别是C ++头文件。另一方面,.h是非C ++头文件(主要是C)。由于存在许多不平凡的情况,因此精确检测内容的语言通常很困难,因此这种差异通常会使易于使用的工具易于编写。对于人类而言,一旦获得约定,它也很容易记住和易于使用。

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

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

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

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

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


0

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

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

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


0

任何特定的扩展都没有任何优势,除了对您,编译器和/或您的工具可能具有不同的含义。 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“内联定义所有功能的头”。

考虑到这一点,主要优点将在于以相同的样式一致地命名标题,并使任何检查您的代码的人都能轻易看到该样式。这样,任何熟悉您惯用的编码风格的人都可以一眼就能看出任何给定扩展名的含义。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.