Answers:
以下是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
或者可以通过相应的.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
编辑 [添加了丹·尼森鲍姆的建议]:
按照惯例,在标头本身中定义原型时,将使用.hpp文件。标头中的此类定义对于模板很有用,因为编译器仅在模板实例化时为每种类型生成代码。因此,如果未在头文件中定义它们,则它们的定义在链接时不会从其他编译单元解析。如果您的项目是仅大量使用模板的C ++项目,则此约定将非常有用。
某些遵守此约定的模板库提供了具有.hpp扩展名的标头,以指示它们没有相应的.cpp文件。
另一种约定是将.h用于C头文件,并将.hpp用于C ++;一个很好的例子是boost库。
引用Boost常见问题解答,
文件扩展名可以将文件的“类型”传达给人类和计算机程序。'.h'扩展名用于C头文件,因此传达了有关C ++头文件的错误信息。不使用扩展名不会传达任何信息,并会强制检查文件内容以确定类型。清楚地使用“ .hpp”将其标识为C ++头文件,并且在实际实践中效果很好。(Rainer Deyke)
我最近开始使用*.hpp
c ++标头。
原因是我将emacs用作主编辑器,并且在加载*.h
文件时它自动进入c模式,而在加载文件时它自动进入c ++模式*.hpp
。
除了这个事实我认为没有充分的理由选择*.h
了*.hpp
,反之亦然。
我在此提醒您,是为了指出我对同一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 当然,我不能说将来的某些版本会带来什么!
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。
我使用.h,因为这是Microsoft使用的,以及它们的代码生成器创建的内容。无需违反常规。
在必读的第1本书《 C ++编程语言,第三版,Bjarne Stroustrup》中,他使用* .h。因此,我认为最佳实践是使用* .h。
但是,*。hpp也可以!
.hpp
语言本身完全没有提及。
工具和人员很容易区分某些东西。而已。
在常规使用中(通过升压等),.hpp
特别是C ++头文件。另一方面,.h
是非C ++头文件(主要是C)。由于存在许多不平凡的情况,因此精确检测内容的语言通常很困难,因此这种差异通常会使易于使用的工具易于编写。对于人类而言,一旦获得约定,它也很容易记住和易于使用。
但是,我要指出,约定本身并不总是如预期的那样有效。
.hpp
本身不是唯一的选择。为什么不.hh
和.hxx
?(尽管如此,通常您至少需要一个关于文件名和路径的常规规则。)我个人同时使用.h
,并.hpp
在我的C ++项目。我没有遵循上述约定,因为:
.h
在github.com上对文件进行语言检测。(在诸如shebang之类的注释中可能有一些内容使这些源文件成为更好的元数据,但它甚至不像文件名那样常规,因此通常也不可靠。)我通常.hpp
在C ++标头上使用,标头应仅以标头的方式使用(维护),例如作为模板库。对于中的其他标头.h
,要么有对应的.cpp
文件作为实现,要么是非C ++标头。后者很容易由人(或需要时使用带有显式嵌入式元数据的工具)通过标头的内容进行区分。
源文件的扩展名可能对您的构建系统有意义,例如,您的makefile中可能包含.cpp
或.c
文件的规则,或者cl.exe
取决于扩展名,编译器(例如Microsoft )可能会将文件编译为C或C ++。
因为您必须将整个文件名提供给#include
指令,所以头文件扩展名无关紧要。.c
如果愿意,可以将文件包含在另一个源文件中,因为它只是文本包含。您的编译器可能有一个选项来转储经过预处理的输出,这将使这一点变得很清楚(Microsoft:/P
对文件进行预处理,对文件/E
进行预处理stdout
,/EP
省略#line
指令,/C
保留注释)
您可能选择使用.hpp
仅与C ++环境相关的文件,即它们使用了无法在C中编译的功能。
任何特定的扩展都没有任何优势,除了对您,编译器和/或您的工具可能具有不同的含义。 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
“内联定义所有功能的头”。
考虑到这一点,主要优点将在于以相同的样式一致地命名标题,并使任何检查您的代码的人都能轻易看到该样式。这样,任何熟悉您惯用的编码风格的人都可以一眼就能看出任何给定扩展名的含义。