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

时间:2008-09-30 10:47:16

标签: c++ header

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

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

20 个答案:

答案 0 :(得分:464)

以下是对C和C ++标题进行不同命名的几个原因:

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

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

答案 1 :(得分:209)

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

答案 2 :(得分:46)

我一直认为.hpp标题是.h.cpp文件的一种形式...一个包含实现细节的标题。

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

答案 3 :(得分:26)

使用哪种扩展名无关紧要。任何一个都可以。

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

答案 4 :(得分:21)

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

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

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

其他一些模板库使用另一种约定,比如使用.h作为C头,使用.hpp作为C ++;一个很好的例子就是升级库。

  

引自Boost FAQ,

     

文件扩展名将文件的“类型”传达给人类   和计算机程序。 '.h'扩展名用于C头   文件,因此传达有关C ++标题的错误信息   文件。使用no extension什么都不通信并强制检查   确定类型的文件内容。毫不含糊地使用'.hpp'   将其标识为C ++头文件,在实际操作中效果很好。   (Rainer Deyke)

答案 5 :(得分:10)

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

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

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

答案 6 :(得分:7)

我正在回答这个问题,以提醒我对“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'个字符,并且取决于<>是否包含该字符,不允许包含>。 或者""包含它的另一种方式 - 包含它不允许包含"

换句话说:如果您的环境支持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扩展提出的提升框架。

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

答案 7 :(得分:6)

您可以随意拨打电话。

只需在#include中指定全名。

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

最终只是一个惯例。

答案 8 :(得分:6)

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

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

答案 9 :(得分:6)

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

答案 10 :(得分:5)

在90年代早期的一项工作中,我们分别使用.cc和.hh作为源文件和头文件。我仍然更喜欢它,可能因为它最容易输入。

答案 11 :(得分:5)

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

所以,当我写一个C ++头文件时,我总是使用.h。

答案 12 :(得分:4)

Bjarne Stroustrup和Herb Sutter在他们的C ++核心指南中发表了对这个问题的陈述:https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#S-source这也引用了标准扩展中的最新变化(C ++ 11,C ++ 14,等)

  

SF.1:对于代码文件使用.cpp后缀,对于接口文件使用.h,如果你的   Y项目还没有遵循另一个惯例   原因

     

这是一项长期的会议。但是一致性更重要,所以如果   你的项目使用其他东西,请遵循。   注意

     

此约定反映了一种常见的使用模式:标题更常被共享   使用C编译为C ++和C,它们通常使用.h和它   更容易命名所有标题.h而不是具有不同的扩展名   只是那些与C共享的标题。另一方面,   实现文件很少与C共享,因此通常应该是   区别于.c文件,因此通常最好命名所有C ++   实现文件的其他东西(例如.cpp)。

     

不需要具体名称.h和.cpp(仅推荐为   默认)和其他名称广泛使用。例如.hh,.C和   .CXX。等价使用这些名称。在本文档中,我们将引用.h和.cpp&gt;作为标题和实现文件的简写,即使是实际的   扩展可能会有所不同。

     

您的IDE(如果您使用的话)可能对有足够的意见。

我不是这个惯例的忠实粉丝,因为如果你使用像boost这样的流行库,你的一致性已经被打破,你应该更好地使用.hpp。

答案 13 :(得分:4)

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

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

答案 14 :(得分:3)

幸运的是,这很简单。

如果你正在使用C ++,你应该使用.hpp扩展名,你应该使用.h代替C或混合使用C和C ++。

答案 15 :(得分:2)

我使用.h因为这是微软使用的,以及他们的代码生成器创建的内容。没必要违背粮食。

答案 16 :(得分:1)

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

在常规使用中(通过boost等),.hpp特别是C ++头文件。另一方面,.h用于非C ++ - 仅标题(主要是C)。要精确检测内容的语言通常很难,因为有许多非平凡的情况,所以这种差异通常使得即用型工具易于编写。对于人类来说,一旦达到惯例,它也易于记忆和易于使用。

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

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

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

  • 明确记录项目各部分使用的语言。没有机会在同一个模块(目录)中混合使用C和C ++。每个第三方图书馆都必须符合此规则。
  • 还记录了项目使用的一致语言规范和允许的语言方言。 (事实上​​,我甚至记录了the source of the standard features and bug fix (on the language standard) being used。)这比区分使用的语言更重要,因为它太容易出错并且测试成本(例如编译器兼容性)可能很大(复杂且耗时) ),特别是在已经几乎纯粹的 C ++的项目中。文件名太弱而无法处理。
  • 即使是相同的C ++方言,也可能有更重要的属性适合差异。例如,请参阅下面的约定。
  • 文件名本质上是脆弱的元数据。违反惯例并不容易被发现。为了稳定处理内容,工具最终不仅要依赖于名称。扩展之间的区别只是一个提示。使用它的工具也不应该一直表现得相同,例如:语法检测github.com上的.h文件。 (对于这些源文件,shebang这样的评论可能会有更好的元数据,但它甚至不像文件名那样传统,所以一般来说也不可靠。)

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

答案 17 :(得分:0)

源文件的扩展名可能对构建系统有意义,例如,您的makefile中可能有.cpp.c文件或编译器(例如Microsoft {{ 1}})可能会根据扩展名将文件编译为C或C ++。

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

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

答案 18 :(得分:0)

在“C ++编程语言,Bjarne Stroustrup的第三版”中,nº1必读的C ++书,他使用* .h。所以我认为最好的做法是使用* .h。

然而,* .hpp也没关系!

答案 19 :(得分:0)

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

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

  1. 如果已有任何既定指南,请遵循这些指南以防止混淆。
  2. 如果项目中的所有源文件都使用相同的语言,请使用.h。没有歧义。
  3. 如果某些标头与多种语言兼容,而其他标头仅与单一语言兼容,则扩展程序基于标头兼容的最严格的语言。与C兼容的标头,或与C&amp; C兼容的标头C ++获取.h,而与C ++兼容而不是C的标题会获得.hpp.hh或类似的东西。
  4. 当然,这只是许多处理扩展程序的方法之一,即使事情看起来很简单,也不一定相信你的第一印象。例如,我已经看到提到使用.h表示普通标题,.tpp表示仅包含模板化类成员函数定义的标题,.h文件定义模板化类,包括.tpp文件定义其成员函数(而不是直接包含函数声明和定义的.h标头)。再举一个例子,很多人总是在其扩展中反映标题的语言,即使没有歧义的可能性;对于他们,.h始终是C标头,.hpp(或.hh.hxx等)始终是C ++标头。而且,有些人使用.h作为“与源文件关联的标题”,并使用.hpp作为“包含内联定义的所有函数的标题”。

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