我一直使用一个*.h
文件来定义我的类,但是在阅读了一些 boost 库代码之后,我意识到它们都使用*.hpp
. 我一直讨厌那个文件扩展名,我想主要是因为我不习惯它。
*.hpp
使用over有什么优点和缺点*.h
?
以下是对 C 和 C++ 头文件进行不同命名的几个原因:
请记住,C不是C++,除非您知道自己在做什么,否则混合搭配可能非常危险。适当地命名您的来源可以帮助您区分语言。
我使用 .hpp 是因为我希望用户区分哪些标头是 C++ 标头,哪些标头是 C 标头。
当您的项目同时使用 C 和 C++ 模块时,这可能很重要:就像我之前解释的其他人一样,您应该非常小心地执行此操作,并且它从您通过扩展提供的“合同”开始
(或.hxx,或.hh,或其他)
此标头仅适用于 C++。
如果您在 C 模块中,甚至不要尝试包含它。你不会喜欢它,因为没有做任何努力使它对 C 友好(会丢失太多,比如函数重载、命名空间等)。
C 源代码和 C++ 源代码都可以直接或间接地包含此标头。
它可以直接包含,受__cplusplus
宏保护:
extern "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
我一直认为.hpp
标头是文件的一种组合.h
....cpp
一个包含实现细节的标头。
通常,当我看到(并使用).hpp
作为扩展名时,没有相应的.cpp
文件。正如其他人所说,这不是一个硬性规定,只是我倾向于使用.hpp
文件的方式。
您使用哪个扩展并不重要。任何一个都可以。
我*.h
用于 C 和*.hpp
C++。
编辑[添加来自 Dan Nissenbaum 的建议]:
按照一种约定,当原型在标头本身中定义时使用 .hpp 文件。头文件中的此类定义在模板的情况下很有用,因为编译器仅在模板实例化时为每种类型生成代码。因此,如果它们没有在头文件中定义,它们的定义将不会在链接时从其他编译单元解析。如果您的项目是一个大量使用模板的纯 C++ 项目,则此约定将很有用。
某些遵循此约定的模板库提供带有 .hpp 扩展名的标头,以表明它们没有相应的 .cpp 文件。
另一个约定是使用 .h 表示 C 头文件,使用 .hpp 表示 C++;一个很好的例子是 boost 库。
引用自 Boost FAQ,
文件扩展名将文件的“类型”传达给人类和计算机程序。'.h' 扩展名用于 C 头文件,因此传达了有关 C++ 头文件的错误信息。不使用扩展名不会传达任何信息并强制检查文件内容以确定类型。使用 '.hpp' 明确地将其标识为 C++ 头文件,并且在实际实践中运行良好。(雷纳·戴克)
我正在回答这个作为提醒,以指出我对“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当然我不能说一些未来的版本会带来什么!
我最近开始使用*.hpp
c++ 标头。
原因是我使用 emacs 作为我的主要编辑器,当你加载文件时它会自动进入 c 模式,当你加载*.h
文件时它会自动进入 c++ 模式*.hpp
。
除了这个事实,我认为没有充分的理由选择*.h
,*.hpp
反之亦然。
你可以随意调用你的includes。
只需要在#include
.
我建议如果您使用 C 来使用.h
,以及何时使用 C++ 来使用.hpp
.
这最终只是一个约定。
我更喜欢 C++ 的 .hpp,以便让编辑和其他程序员都清楚它是 C++ 头文件而不是 C 头文件。
C++(“C Plus Plus”)作为 .cpp 是有意义的
具有 .hpp 扩展名的头文件没有相同的逻辑流程。
Codegear C++Builder 将 .hpp 用于从 Delphi 源文件自动生成的头文件,并将 .h 文件用于“自己的”头文件。
因此,当我编写 C++ 头文件时,我总是使用 .h。
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。
在 90 年代初我的一项工作中,我们分别使用 .cc 和 .hh 作为源文件和头文件。我仍然更喜欢它而不是所有替代品,可能是因为它最容易打字。
幸运的是,这很简单。
如果您使用 C++,您应该使用 .hpp 扩展名,并且您应该将 .h 用于 C 或混合使用 C 和 C++。
正如这里的许多人已经提到的,我也更喜欢将 .hpp 用于使用模板类/函数的仅标头库。我更喜欢将 .h 用于带有 .cpp 源文件或共享或静态库的头文件。
我开发的大多数库都是基于模板的,因此只需要作为头文件,但是在编写应用程序时,我倾向于将声明与实现分开,最终得到 .h 和 .cpp 文件
工具和人类很容易区分某些东西。就是这样。
在常规使用中(通过 boost 等),.hpp
特别是 C++ 头文件。另一方面,.h
适用于非 C++-only 头文件(主要是 C)。精确检测内容的语言通常很困难,因为有很多不平凡的案例,因此这种差异通常使现成的工具易于编写。对人类来说,一旦得到约定,它也很容易记住和使用。
但是,我要指出,约定本身并不总是如预期的那样有效。
.hpp
本身并不是唯一的选择。为什么不呢.hh
?.hxx
(尽管如此,您通常至少需要一个关于文件名和路径的常规规则。)我个人在我的 C++ 项目中.h
都使用它们。.hpp
我不遵循上述约定,因为:
.h
github.com 上文件的语言检测。(在shebang之类的评论中可能有一些东西让这些源文件成为更好的元数据,但它甚至不像文件名那样传统,因此通常也不可靠。)我通常.hpp
在 C++ 头文件上使用,并且头文件应该以仅头文件的方式使用(维护),例如作为模板库。对于 中的其他头文件.h
,要么有相应的.cpp
文件作为实现,要么是非 C++ 头文件。后者通过人类(或通过具有显式嵌入元数据的工具,如果需要)来区分标题的内容是微不足道的。
我使用 .h 是因为这是 Microsoft 使用的,也是他们的代码生成器创建的。没有必要违背粮食。
在“The C++ Programming Language, Third Edition by Bjarne Stroustrup”,第一本 C++ 必读书籍,他使用 *.h。所以我认为最好的做法是使用 *.h。
但是,*.hpp 也可以!
任何特定扩展都没有任何优势,除了对您、编译器和/或您的工具可能有不同的含义。 header.h
是一个有效的标头。 header.hpp
是一个有效的标头。 header.hh
是一个有效的标头。 header.hx
是一个有效的标头。 h.header
是一个有效的标头。 this.is.not.a.valid.header
是拒绝的有效标头。 ihjkflajfajfklaf
是一个有效的标头。只要名称可以被编译器正确解析,并且文件系统支持它,它就是一个有效的标头,其扩展的唯一优势就是人们读入它的内容。
话虽如此,能够根据扩展名准确地做出假设是非常有用的,因此为您的头文件使用一组易于理解的规则是明智的。就个人而言,我更喜欢这样做:
.h
. 没有歧义。.h
兼容的标头获取 ,而与 C++ 兼容但不与 C 兼容的标头获取.hpp
或.hh
类似的东西。当然,这只是处理扩展的众多方法之一,即使事情看起来很简单,您也不一定相信您的第一印象。例如,我看到提到使用.h
普通头文件,以及.tpp
只包含模板类成员函数定义的头.h
文件,定义模板类的.tpp
文件包括定义其成员函数的文件(而不是.h
直接包含两个函数声明和定义)。再举一个例子,很多人总是在其扩展中反映标题的语言,即使没有歧义的可能性。对他们来说,.h
总是一个 C 头文件和.hpp
(或.hh
,或.hxx
等)始终是 C++ 标头。再一次,有些人使用.h
“与源文件关联的标头”和.hpp
“具有内联定义的所有函数的标头”。
考虑到这一点,主要优势在于始终以相同的样式命名您的标题,并使该样式对任何检查您的代码的人都很明显。这样,任何熟悉您通常的编码风格的人都可以通过粗略的一瞥来确定您对任何给定扩展的含义。
源文件的扩展名可能对您的构建系统有意义,例如,您的 makefile 中可能有一个规则用于.cpp
或.c
文件,或者您的编译器(例如 Microsoft cl.exe
)可能会根据扩展名将文件编译为 C 或 C++。
因为您必须为#include
指令提供整个文件名,所以头文件扩展名是无关紧要的。.c
如果您愿意,您可以在另一个源文件中包含一个文件,因为它只是一个文本包含。您的编译器可能有一个选项来转储预处理的输出,这将使这一点变得清晰(微软:/P
预处理到文件,/E
预处理到stdout
,/EP
省略#line
指令,/C
保留注释)
您可能会选择.hpp
用于仅与 C++ 环境相关的文件,即它们使用不会在 C 中编译的功能。