cmath vs math.h(以及类似的 c 前缀 vs .h 扩展头文件)

Posted

技术标签:

【中文标题】cmath vs math.h(以及类似的 c 前缀 vs .h 扩展头文件)【英文标题】:cmath vs math.h (And similar c-prefixed vs .h extension headers) 【发布时间】:2012-05-28 11:38:28 【问题描述】:

我看到了一些关于 iostreamiostream.h 之间差异的信息。根据我从这些中收集到的信息,它们之间的区别在于,没有 .h 扩展名的版本不会填充命名空间,而带有扩展名的版本会。

cmathmath.h 是否相同?为什么cmath(以及许多其他类似的文件)以c 为前缀,而不仅仅是math?它们之间还有更多的区别吗?

【问题讨论】:

请参阅***.com/q/2118422 和***.com/q/2587445 了解相关(但可能不是欺骗)问题。 【参考方案1】:

我已经看到了一些关于 iostream 与 iostream.h 之类的差异的信息。

[iostream.h] 不是标准头文件。

这不是您提出的问题的示例。

[cmath] 在std 命名空间中定义符号,也可以在全局命名空间中定义符号。 [math.h] 在全局命名空间中定义符号,也可以在std 命名空间中定义符号。如果您包含前者并使用非限定符号,则它可以用一个编译器编译,但不能用另一个编译器编译。因此使用 [math.h] 是个好主意。通常,对于此类标头对,使用 [.h] 版本。

c++98 提供了 cxxx 标头不会污染全局命名空间的正式保证。也许这就是他们被定义的原因。然而,这比污染的实现要难一些,所以在实践中,我所知道的标准库实现在这方面没有遵循标准,所以它最终被改变以反映 c++11 中的现实。

【讨论】:

therefore it's a good idea to use [math.h]. and in general, for such header pairs, to use the [.h] version. 我不同意。 .h 版本存在的唯一原因是为了兼容性。 C 头文件列在 [depr.c.headers] 下是有原因的。 @Jesse:论点是,如果您包含math.h,那么您知道您将在全局命名空间中丢弃一堆垃圾。如果您包含cmath,那么您可能会或可能不会在全局命名空间中丢弃一堆垃圾。相反,您不在乎是否在命名空间std 中丢了一堆垃圾,因为无论如何您都不会在其中定义符号。所以在某种意义上,math.h 做什么的不确定性比cmath 做什么的不确定性要好,不管委员会是怎么想的。 最终,该标准明确地说明了您允许写什么,并且还考虑了写什么明智。没有规则说委员会总是明智的,即使通常是这样,而且从根本上说,这些标题是不同类型的坏事之间的混乱折衷。我个人使用cmath 并希望不要编写我的实现没有捕获的错误(这是 C++03 中的一致性失败和 C++11 中的 QoI 问题),但其他人有不同的优先级。 5 年后我坐在这里想知道我是否应该在我的 C++ (11) 程序中使用 cmathmath.hheader。哪一个?从这个答案和一些 cmets 的受欢迎程度来看,我认为我应该使用 math.h? 非常糟糕的建议,<math.h> 从 C++11 开始在 C++ 标准中已弃用,这意味着编译器仅支持它以实现向后兼容性。这意味着您无法保证每个实现在 x.h 标头中的内容,因为它们不是标准的。事实上,在某些情况下,x.h 版本有时与 cx 版本在某些实现上具有不同的内容,其中重载的行为不同,这可能令人惊讶。因此,如果您正在编写 C++,请始终使用 <cx> 标头。【参考方案2】:

也许这会有所帮助:

C++ 库包含与 C 语言相同的定义 库组织在相同的头文件结构中,具有 以下区别:

1 - 每个头文件与 C 同名 语言版本,但带有“c”前缀且没有扩展名。例如, C 语言头文件 的 C++ 等效项是 .

2 - 库的每个元素都在 std 命名空间中定义。

c-prefixed vs .h extension headers

【讨论】:

【参考方案3】:

名称以c 开头的头文件来自C 标准库的头文件。删除了 c 前缀并添加了 .h 后缀的相应标头与 C 标准库标头相同(或几乎相同)。

<cmath>定义了std命名空间下的相关符号; <math.h> 全局定义它们。

(我刚刚了解到这并不那么简单;请参阅 Alf 的回答。)

【讨论】:

-1 不,以c 开头的头文件是 C 标准库头文件的 C++ 特定变体。它们不是来自 C 库。另外,不能保证cmath 没有定义全局命名空间中的符号,也不能保证math.h 没有定义std 命名空间中的符号。 @Cheersandhth.-Alf:我的措辞草率;我并不是说“来自 C 标准库”来暗示它们直接来自 C 标准库。我不知道<cmath> 可以定义全局符号,<math.h> 可以定义std 命名空间中的符号。现在我知道了,我很困惑;为什么 C++ 标准保留该实现定义? @KeithThompson:因为它反映了现实。许多标准库实现已经这样做了很长时间。标准委员会没有强制实施对这个问题更加严格(经验表明这并没有达到预期的效果),而是放宽了程序员的期望。 @AndréCaron:我在这个问题的评论链接的问题中看到了这一点。我觉得这令人失望。 @krvajal:这是一个 69 分钟的 C++ 标准库小组讨论视频。您有适合评论的摘要吗?【参考方案4】:

<cmath> 和任何 <cxxx> 标头都是标准 C++,这意味着您对这些标头中支持的内容以及它们中的函数如何工作有强有力的保证,如 C++ 标准中所述。它们在std 命名空间中定义了一系列函数,仅此而已。

<math.h> 和任何 <xxx.h> 标头不是标准 C++,尽管每个主要实现都支持。 但是,由于它们已被弃用,当您将它们包含在这些标题中时,没有保证这些标题中的内容你的实施。事实上,在某些实现中已经观察到它们提供的功能与<cxxx> 版本的行为不同

因此,在编写 C++ 时应始终使用<cxxx>,并使用std:: 限定函数的名称,例如std::malloc

【讨论】:

using namespace std;

以上是关于cmath vs math.h(以及类似的 c 前缀 vs .h 扩展头文件)的主要内容,如果未能解决你的问题,请参考以下文章

为啥 GCC 为 C++ <cmath> 实现 isnan() 比 C <math.h> 更有效?

C++中的cmath头文件

C++中的<math>和<cmath>有啥区别

C++标准库中是不是有类似math的库,有叫mathematic的库

在<math.h>中都有哪些函数?

开发 C,math.h 问题