C ++标准是否需要`#include <math.h>`来定义`<cmath>`中的`abs`重载?

时间:2016-05-04 21:10:09

标签: c++ c++-standard-library math.h

C ++标准在<cmath>标头中定义了一些不属于C中<math.h>标头的重载函数(因为C没有重载)。 其中包括float abs(float)double abs(double)long double abs(long double)double abs(Integral)。 另一方面,abs中根本没有定义<math.h>(而是<stdlib.h>),唯一的签名是int abs(int)

现在在我的系统上,当使用带有C ++程序的C ++编译器时,#include <math.h>不会在全局命名空间或abs中提供C ++ std重载。 另一方面,#include <cmath>定义std::abs

这是我所期望的 - 包括用于获取C函数的C版本,并包含C ++版本以获得C ++函数。 @visitor This answer提到了同样的事情。

然而,用户@ Cheers-and-hth-Alf坚持认为这违反了标准,因为它说“每个C标头,每个标头都有一个name.h形式的名称”,表现得好像由相应的 cname 标头放置在标准库命名空间中的每个名称都放在全局命名空间范围内。“ (本节D.5.2在C ++ 03,C ++ 11和C ++ 14之间似乎没有太大变化。)

很容易检查你的平台做了什么:看看

会发生什么
#include <math.h>

int main() {
    abs(1.2);
    return 0;
}

如果未声明abs,则<math.h>不包含C ++函数。

如果编译,请尝试包含<stdio.h> 并添加printf("%g\n", abs(1.2)); 如果这会抱怨格式不匹配,或打印1,那么<math.h> 包括C int abs(int)函数(通常在<stdlib.h>中)。 (最好避免<iostream>和其他C ++标题,因为它们往往会引入<cstdlib>并混淆问题。)

这是我发现的:

GNU libstdc ++

$ g++ -Wall -Wextra abs2.cc -o abs2
abs2.cc: In function 'int main()':
abs2.cc:5:22: error: 'abs' was not declared in this scope
  std::cout << abs(1.2) << '\n';

libstdc++ docs on the subject 建议包括C ++样式标题<c*>而不是C样式标题<*.h>正是因为 C ++风格的头文件使用函数重载,而C风格的头文件没有。

Apple libc ++

$ clang++ -Wall -Wextra abs2.cc -o abs2
abs2.cc:4:5: error: use of undeclared identifier 'abs'; did you mean 'fabs'?

此外,如果您还包含<stdlib.h>以获取abs的定义,则clang ++给出 更有用的错误消息

abs2.cc:5:5: warning: using integer absolute value function 'abs' when argument is of floating point type [-Wabsolute-value]
    abs(1.2);
    ^
abs2.cc:5:5: note: use function 'std::abs' instead
    abs(1.2);
    ^~~
    std::abs
abs2.cc:5:5: note: include the header <cmath> or explicitly provide a declaration for 'std::abs'
abs2.cc:5:9: warning: implicit conversion from 'double' to 'int' changes value from 1.2 to 1 [-Wliteral-conversion]
    abs(1.2);
    ~~~ ^~~
abs2.cc:5:5: warning: ignoring return value of function declared with const attribute [-Wunused-value]
    abs(1.2);
    ^~~ ~~~

这明确说明浮点重载只能从<cmath>获得,而不是来自。{1}} C传统标题。

Apache libstdcxx

我没有安装它,但是检查math.h header,它将<cmath>中那些也在C <math.h>中定义的函数带入全局命名空间,但不包括{ {1}}。

OpenWatcom C ++

再次检查cmath/math.h header, 当用作abs时,它将相同的函数带入Apache libstdcxx所做的全局命名空间,不包括math.h

STLPort的

检查math.h header,它包含系统的C abs标头,它不是C ++库的一部分,因此不包括<math.h>。 (这也是g ++和clang ++所做的。)

Microsoft Visual Studio(Dinkumware)

我自己没有访问权限, 但this site声称使用Visual C ++进行编译, 它说

abs

因此,字面上每个主要的C ++标准库实现 在这一点上违反标准?

或者我们是否遗漏了标准中关于error C4578: 'abs': conversion from 'double' to 'int', possible loss of data (Did you mean to call 'fabs' or to #include <cmath>?) 和其他传统C标头的内容?

1 个答案:

答案 0 :(得分:1)

&#34;每个C头,每个头都有一个名称为name.h的行为,就好像每个名称放在标准库命名空间中的相应cname头一样放在全局命名空间范围。&#34;

对我而言,这句话并未说明<cname>标题中的每个名称都必须出现在name.h标题中。

它表示在<name.h>标头中<cname>标题 中具有相应名称 的每个名称都必须出现在全局名称空间中。

它没有说明<cname>标题中未出现在<name.h>标题中的名称。

  

C ++ 14 Stadard

     

D.5 C标准库标题 [ depr.c.headers ]

     

为了与C标准库和C Unicode TR兼容,C ++标准库提供 26 C头,如表

所示。

此声明使用术语&#34; 26 C标题&#34;建议它们包含C标准中应包含的内容,而不是C++标准中<cname>应包含的内容。

事实上,关于<cstddef>,例如,它会在相应的C标题中详细说明未包含的内容。

<强>例如

  

18.2类型 [ support.types ]

     

2 内容与标准C库标题<stddef.h>相同,但有以下更改......