* .h或* .hpp用于您的类定义
我一直使用一个*.h
文件作为我的类定义,但是在阅读了一些boost库代码后,我意识到它们都使用*.hpp
。 我总是厌恶这个文件扩展名,我想主要是因为我不习惯。
使用*.hpp
不是*.h
的优点和缺点是什么?
这里有几个C和C ++头文件命名不同的原因:
- 自动代码格式化,您可能有不同的格式化C和C ++代码的指导原则。 如果标题以扩展名分隔,则可以将您的编辑器设置为自动应用适当的格式
- 命名,我一直在用C编写库,然后用C ++实现包装器的项目。 由于标题通常有相似的名称,即Feature.h对Feature.hpp,他们很容易分开。
- 包含,也许你的项目有更多的适当的版本可用C ++编写,但你使用的是C版本(见上面的观点)。 如果头文件是按照实现的语言来命名的,你可以很容易地find所有的C头文件并检查C ++版本。
请记住,C 不是 C ++,除非你知道自己在做什么,否则混合搭配会非常危险。 恰当地命名你的资源可以帮助你区分不同的语言。
我使用.hpp是因为我想让用户区分C ++头文件和C头文件。
当您的项目同时使用C和C ++模块时,这一点很重要:就像别人之前解释的一样,您应该非常小心地做,并且从您通过扩展提供的“合同”开始
.hpp:C ++头文件
(或.hxx,或.hh,或其他)
这个头只用于C ++。
如果你在C模块中,甚至不要尝试包含它。 你不会喜欢它,因为没有努力使它对C友好(太多会丢失,像函数重载,命名空间等)。
.h:C / C ++兼容或纯C头
这个头文件可以直接或间接地被C源代码和C ++源代码包含。
它可以直接包含在__cplusplus
macros的保护下:
- 这意味着,从C ++的angular度来看,C兼容的代码将被定义为
extern "c"
。 - 从C的angular度来看,所有的C代码都将清晰可见,但C ++代码将被隐藏(因为它不会在C编译器中编译)。
例如:
#ifndef MY_HEADER_H #define MY_HEADER_H #ifdef __cpluplus extern "C" { #endif void myCFunction() ; #ifdef __cpluplus } // 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
头文件是一个.h
和.cpp
文件的头文件,它也包含实现细节。
通常当我看到(并使用) .hpp
作为扩展名时,没有对应的.cpp
文件。 正如其他人所说,这不是一个硬性规定,只是我倾向于使用.hpp
文件。
使用哪个扩展名并不重要。 任何一个都可以。
我使用*.h
为C和*.hpp
为C ++。
编辑 [添丹尼森鲍姆build议]:
按照一个约定,在头文件中定义原型时使用.hpp文件。 头文件中的这种定义在模板的情况下非常有用,因为编译器仅在模板实例化时为每种types生成代码。 因此,如果它们没有在头文件中定义,它们的定义将不会在其他编译单元的链接时被parsing。 如果你的项目是一个大量使用模板的C ++项目,这个约定可能是有用的。
遵循这个约定的某些模板库提供带有.hpp扩展名的头部,以表明它们没有对应的.cpp文件。
其他一些模板库使用另一个约定,例如对于C标头使用.h而对C ++使用.hpp; 助推库是一个很好的例子。
来自Boost FAQ的报价,
文件扩展名将文件的“types”传递给人类和计算机程序。 “.h”扩展名用于C头文件,因此传递了有关C ++头文件的错误信息。 使用没有扩展的通信并强制检查文件内容以确定types。 使用'.hpp'明确地将其识别为C ++头文件,并且在实际中运行良好。 (Rainer Deyke)
我最近开始使用*.hpp
for c ++头文件。
原因是我使用emacs作为我的主编辑器,当您加载*.h
文件时,它会自动进入c模式,而在加载*.hpp
文件时会自动进入c ++模式。
除此之外,我看不到select*.h
over *.hpp
或反之亦然的好理由。
在我90年代初的工作中,我们分别使用.cc和.hh作为源文件和头文件。 我仍然比较喜欢它,可能是因为它最容易input。
我更喜欢C ++的.hpp文件,使编辑和其他程序员都清楚它是C ++头文件而不是C头文件。
C ++(“C Plus Plus”)与.cpp相似
具有.hpp扩展名的头文件不具有相同的逻辑stream。
我正在回答这个提醒,指出我对“user1949346”的评论(s)回答了这个同样的OP。
所以许多人都已经回答:无论哪种方式都没有问题。 其次是强调自己的印象。
在前面提到的那样,我也认为C++
头文件扩展名是.h
如果实际上没有任何理由反对的话。
由于ISO / IEC文档使用这种头文件的表示法,并且没有与.hpp
匹配的string甚至出现在关于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.>>
将是无效的。 另一方面也是如此。
由于文件名本身已经解释,即使这将符合C++
,这将是一个非常愚蠢的想法。
这就是为什么.hpp
也是有效的。
但不是委托人devise语言的结果!
因此,讨论即将使用.hpp
方法与.cc
, .mm
相同,或者我在其他文章中阅读的内容。
我不得不承认,我不知道.hpp
从哪里来,但我敢打赌,一个parsing工具的发明者,IDE或其他与C++
有关的人来到这个想法来优化一些内部的过程,或者只是发明一些(可能甚至是必要的)新的命名召集。
但这不是语言的一部分。
而且每当决定以这种方式使用它。 可能是因为他最喜欢它,或者因为工作stream程的一些应用程序需要它,所以它从来不是语言的要求。 所以谁曾经说过“pp是因为它和C ++一起使用”,那简直是错误的。
C ++允许任何尊重前一段的内容。 如果有什么委员会提出使用的话,那就是使用.h
因为这是ISO文件所有例子中的延伸。
结论:
只要你没有看到/觉得有必要使用.hpp
或者反过来,你不应该打扰。 因为两者都将形成与标准相同质量的有效标题名称。 因此,任何需要使用.h
或.hpp
都是对标准的额外限制,甚至可能与其他附加限制不.hpp
。 但是,由于OP没有提到任何额外的语言限制,这是唯一正确和可以接受的答案
“ * .h或* .hpp为您的类定义 ”是:
只要没有外部限制,两者都是正确的和适用的。
1 当然,我不能说将来的版本会带来什么!
你可以打电话给你的包括任何你喜欢的。
只需要在#include
指定全名。
我build议如果你使用C来使用.h
和C ++来使用.hpp
。
这只是一个惯例。
Codegear C ++ Builder使用.hpp作为Delphi源文件自动生成的头文件,.h文件作为你自己的头文件。
所以,当我写一个C ++头文件时,我总是使用.h。
我使用.h因为这是Microsoft使用的,以及他们的代码生成器创build的。 没有必要违背粮食。
工具和人类很容易区分一些东西 。 而已。
在传统的使用中(通过boost等) .hpp
是特定的C ++头文件。 另一方面, .h
是用于非C ++的头文件(主要是C)。 为了精确地检测内容的语言通常很困难,因为有许多不平凡的情况,所以这种差异通常使得易于使用的工具容易编写。 对于人类来说,一旦习惯了,也很容易记忆,易于使用。
不过,我想指出,这个惯例本身并不总是如预期的那样工作。
- 它不是由语言的规范所强制的 ,既不是C也不是C ++。 有许多项目不符合惯例。 一旦你需要合并(混合)他们,这可能是麻烦的。
-
.hpp
本身并不是唯一的select。 为什么不.hh
或.hxx
? (尽pipe无论如何,您通常至less需要一个关于文件名和path的常规规则。)
我个人在我的C ++项目中使用.h
和.hpp
。 我不遵循上面的惯例,因为:
- 项目的每个部分使用的语言都有明确的logging。 没有机会在同一个模块(目录)中混合使用C和C ++。 每个第三方图书馆都必须符合这一规定。
- 还logging了符合的语言规范和项目使用的语言方言。 (事实上,我甚至logging了使用的标准function和错误修复(在语言标准上)的来源 。)这比区分使用的语言更重要,因为它太容易出错,并且testing成本(例如编译器兼容性)可能是重要的(复杂和耗时),特别是在已经几乎纯粹的 C ++的项目中。 文件名太弱,无法处理。
- 即使对于相同的C ++方言,也可能有更适合差异的重要属性。 例如,请参阅下面的约定。
- 文件名基本上是脆弱的元数据。 违反惯例不容易察觉。 为了稳定处理内容,一个工具最终不仅要取决于名称。 扩展之间的区别只是一个提示。 使用它的工具也不应该被期望一直performance相同,例如github.com上的
.h
文件的语言检测。 (这些源文件可能会有一些像这样的注释文件,可能是更好的元数据,但它甚至不像传统文件名那样常规,所以一般来说也不可靠。)
我通常在C ++头文件中使用.hpp
,头文件只能以头文件的方式使用(维护),例如作为模板库。 对于.h
其他头文件,要么有相应的.cpp
文件作为实现,要么是非C ++头文件。 后者通过人的头部内容(或者如果需要,通过具有显式embedded的元数据的工具)来区分是微不足道的。
Bjarne Stroustrup和Herb Sutter在他们的C ++ Core指南中对这个问题有了一个声明: 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共享。另一方面,实现文件很less与C共享,因此通常应该将其与.c文件区分开来,所以通常最好将所有C ++实现文件命名为其他文件(如.cpp)。
特定的名称.h和.cpp不是必需的(只是build议作为默认值),其他名称已被广泛使用。 例子是.hh,.C和.cxx。 等效使用这样的名字。 在本文档中,我们将.h和.cpp>作为头文件和实现文件的简写,尽pipe实际的扩展名可能不同。
你的IDE(如果你使用的话)可能会有足够的关于足够的意见。
我不是这个惯例的忠实粉丝,因为如果你正在使用像boost这样的stream行库,你的一致性已经被破坏,你应该更好地使用.hpp。
源文件的扩展名可能对您的编译系统有意义,例如,您的makefile中可能有.cpp
或.c
文件的规则,或者您的编译器(例如Microsoft cl.exe
)可能会将该文件编译为C或C ++取决于扩展名。
由于必须将整个文件名提供给#include
指令,所以头文件扩展名是不相关的。 如果你喜欢,你可以在另一个源文件中包含一个.c
文件,因为这只是一个文本包含。 您的编译器可能有一个选项来转储预处理的输出,这将清除(Microsoft: /P
预处理文件, /E
预处理为stdout
, /EP
省略#line
指令, /C
保留注释)
您可以select使用.hpp
作为仅与C ++环境相关的文件,也就是说,它们使用不能在C中编译的function。
对于任何特定的扩展,没有任何优势,除了可能对您,编译器和/或您的工具有不同的含义。 header.h
是一个有效的头。 header.hpp
是一个有效的标题。 header.hh
是一个有效的标题。 header.hx
是一个有效的标题。 h.header
是一个有效的头文件。 this.is.not.a.valid.header
是拒绝的有效头。 ihjkflajfajfklaf
是一个有效的标题。 只要编译器可以正确parsing名称,并且文件系统支持它,那么它就是一个有效的头文件,扩展的唯一好处就是读入头文件。
这就是说,能够准确地做出基于扩展的假设是非常有用的,因此,对头文件使用容易理解的一组规则是明智的。 就个人而言,我更喜欢做这样的事情:
- 如果已经有了既定的指导方针,请遵循它们以防止混淆。
- 如果项目中的所有源文件都使用相同的语言,请使用
.h
。 没有歧义。 - 如果某些标题与多种语言兼容,而其他标题仅与单一语言兼容,则扩展名基于标题兼容的限制性最强的语言。 与C兼容的头文件或与C&C ++兼容的头文件都会得到
.h
,而与C ++兼容的头文件却不会得到.hpp
或.hh
或类似的东西。
当然,这只是处理扩展的许多方法之一,即使看起来很简单,你也不一定会相信你的第一印象。 例如,我曾经提到使用.h
作为普通标题,而.tpp
作为仅包含模板类成员函数定义的标题,使用.h
文件定义模板类,包括定义其成员函数的.tpp
文件而不是直接包含函数声明和定义的.h
头文件)。 再比如,很多人总是在扩展中反映标题的语言,即使没有模棱两可的可能性, 对他们来说, .h
总是一个C头,而.hpp
(或.hh
或.hxx
等)总是一个C ++头。 还有一些人使用.h
作为“与源文件关联的标题”,而.hpp
作为“所有函数内联定义的标题”。
考虑到这一点,主要的优势在于始终如一地将头文件命名为相同的样式,并且使得这种风格对于任何人来说都是显而易见的。 通过这种方式,任何熟悉您惯用的编码风格的人都可以通过粗略的浏览来确定您的扩展名。
正如这里已经提到的那样,我还更喜欢使用.hpp作为使用模板类/函数的仅包含头文件的库。 我更喜欢使用.h作为.cpp源文件或共享或静态库的头文件。
我开发的大多数库都是基于模板的,因此只需要作为头文件,但是在编写应用程序时,我倾向于将声明与实现分开,最后使用.h和.cpp文件
在“The C ++ Programming Language,Bjarne Stroustrup第三版”一书中,他使用了* .h。 所以我认为最好的做法是使用* .h。
但是,* .hpp也不错!
幸运的是,这很简单。
如果使用C ++,则应该使用.hpp扩展名,并且应该使用.h作为C或混合使用C和C ++。