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

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

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

415624 次浏览

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

我用*.h表示C,用*.hpp表示C++。

你可以叫你的包括任何你喜欢的。

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

我建议如果你使用C使用.h,当使用C++使用.hpp

这最终只是一个惯例。

CodeGearC++Builder使用. hpp作为从Delphi源文件自动生成的头文件,使用. h文件作为“自己的”头文件。

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

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

我最近开始使用*.hpp作为c++头文件。

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

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

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

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

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

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

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

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

C++我更喜欢. hpp,以便向编辑和其他程序员表明它是C++头文件而不是C头文件。

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

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

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

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

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

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

在“C++编程语言,Bjarne Stroustrup的第三版”这本必读C++书中,他使用了*. h。

但是,*. hpp也很好!

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

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

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

另一个惯例是使用. h作为C头文件,使用. hpp作为C++;一个很好的例子是提升库。

订阅关于Boost FAQ的评论:

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

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

在常规的使用中(通过Boost等),.hpp专门C++标题。另一方面,.h用于非C++的标题(主要是C语言)。由于有许多非平凡的案例,要精确检测内容的语言通常是困难的,所以这种差异通常使得即用型工具易于编写。对于人类来说,一旦得到约定,它也很容易记住和使用。

然而,我要指出,公约本身并不总是像预期的那样有效。

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

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

  • 项目每个部分使用的语言都有明确的文档记录。没有机会将C和C++混合在同一个模块(目录)中。每个第三方库都需要遵守这条规则。
  • 项目使用的语言规范和允许的语言方言也被记录下来。(事实上,我甚至记录了标准功能的来源和正在使用的bug修复(基于语言标准)。)这比区分使用的语言更重要,因为它太容易出错,测试成本(例如编译器兼容性)可能很大(复杂且耗时),尤其是在一个已经在几乎纯净C++的项目中。文件名太弱,无法处理这个问题。
  • 即使对于相同的C++方言,也可能有更重要的属性适合这种差异。例如,参见下面的约定。
  • 文件名本质上是脆弱的元数据。违反约定并不容易被检测到。为了稳定地处理内容,工具最终应该不仅仅依赖于名称。扩展名之间的区别只是一个提示。使用它的工具也不应该一直表现相同,例如github.com.上.h文件的语言检测(在sheband之类的注释中可能会有一些东西让这些源文件成为更好的元数据,但它甚至不像文件名那样常规,所以总体上也不可靠。)

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

我回答这个作为一个提醒,给点我的评论(S)“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:
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++,这将是一个非常非常愚蠢的想法,tho。

这就是为什么.hpp也是有效的。

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

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

我必须承认我不知道.hpp来自1,但我敢打赌,一些解析工具的发明者,IDE或其他与C++有关的东西来优化一些内部流程,或者只是为了发明一些(甚至可能是为了他们)新的命名约定。

但它不是语言的一部分。

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

C++允许任何关于上一段的内容。 如果委员会建议使用任何东西,那么它就是使用.h,因为这是ISO文件所有示例中的扩展。

结论:

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

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

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


1据我所知,显然,它是提出.hpp扩展的提升框架。

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或类似的东西。

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

考虑到这一点,主要的优势在于始终以相同的风格命名您的标题,并且让任何检查您的代码的人都可以很明显地看到这种风格。这样,任何熟悉您通常的编码风格的人都将能够粗略地了解您对任何给定扩展的含义。

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

SF1:如果您的代码文件使用. cpp后缀,接口文件使用. h Y项目没有遵循另一个约定 原因

这是一个由来已久的惯例。但是一致性更重要,所以如果 你的项目使用其他东西,遵循它。 注意

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

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

您的IDE(如果您使用IDE)可能对是否足够有强烈的意见。

我不是这个约定的忠实粉丝,因为如果你使用的是一个流行的库,比如boop,你的一致性已经被破坏了,你应该更好地使用. hpp。

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

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

幸运的是,这很简单。

如果您正在使用C++,则应该使用. hpp扩展名,并且应该使用. h表示C或混合C和C++。