【问题标题】:abs vs std::abs, what does the reference say?abs vs std::abs,参考说明了什么?
【发布时间】:2014-02-18 23:40:06
【问题描述】:

注意,我说的是::abs(),而不是std::abs()

根据cplusplus.com websiteabs 的行为应该与stdlib.h C 版本不同,如果您包含<cmath>

这是此页面的摘录(涉及::abs,而不是std::abs):

double abs (double x); 
float abs (float x); 
long double abs (long double x);
Compute absolute value
/*
Returns the absolute value of x: |x|.
These convenience abs overloads are exclusive of C++. In C, abs is only declared
in  <cstdlib> (and operates on int values). 
The additional overloads are provided in this header (<cmath>) for the integral types: 
These overloads effectively cast x to a double before calculations 
(defined for T being any integral type).
*/

真的???

在将程序移植到新平台时,我一直被这个问题困扰,因为不同的编译器和标准库的实现在这里有所不同。

这是我的示例程序:

#include <iostream>
//#include <stdlib.h>//Necessary inclusion compil under linux
//You can include either cmath or math.h, the result is the same
//#include <cmath>
#include <math.h>
int main(int argc, const char * argv[])
{
  double x = -1.5;
  double ax = std::abs(x);
  std::cout << "x=" << x << " ax=" << ax << std::endl;
  return 0;
}

这是 MSVC 2010 下的结果:

  • 在 MSVC 2010 下不会发出编译警告,即使您既不包含 math.h 也不包含 stdlib.h,程序也会编译:似乎无论您做什么,总是包含 math.hstdlib.h李>
  • 程序输出为:x=-1.5 ax=1.5(根据参考资料貌似正确)

现在是 OSX 下的结果:

  • 即使带有-Wall 标志,也不会发出编译警告(未发出双精度转换为int 的信号)!如果将g++ 替换为llvm-g++,结果是一样的。编译不需要包含math.hcmath
  • 程序输出为:x=-1.5 ax=1

最后是Linux下的结果:

  • 如果不包含stdlib.h,程序将无法编译(最后,一个不包含stdlib的编译器自动)。对于 double -> int cast,不会发出编译警告。
  • 程序输出为:x=-1.5 ax=1

这里没有明确的赢家。我知道一个明显的答案是“更喜欢std::abs 而不是::abs”,但我想知道:

  • 当 cplusplus.com 网站说 abs 应该在 std 命名空间之外自动提供双重版本时,是否就在这里?
  • 除了 MSVC 之外,所有编译器及其标准库都错了吗(尽管它默默地包含 math.h)?

【问题讨论】:

  • cstdlib 不是 C 标头,因此 cplusplus.com 在那里是错误的(惊喜)。另请注意,包含iostream 可能会造成混淆,因为它可以包含cmath 和/或cstdlib,这两者都可能在全局命名空间中引入各种abs 重载。所以摆脱它。
  • “双精度转换为 int 没有信号” - 你的代码中没有双精度转换。 “cplusplus.com 是否正确” - 我不知道, 但 cplusplus.com 因包含不正确和/或误导性信息而臭名昭著,所以我的猜测是“不, cplusplus.com 是错误的”。这同样适用于 MSVC(如果 3 个编译器同意而 MSVC 不同意,那么很可能 MSVC 是错误的,但同样,我不知道,我不是 C++ 程序员。)
  • cplusplus.com 是一个非常糟糕的资源。 C 标准中没有&lt;cstdlib&gt;。说“在 C 中,abs 只在 中声明”是错误的。
  • 我会知道 cplusplus.com 的资源不够精确,谢谢!
  • “处理::abs,而不是std::abs” – 呃,你是怎么知道的?

标签: c++ cmath


【解决方案1】:

官方参考资料说……这是一团糟。 C++11 和 C11 之前的版本:

  • 官方,包括&lt;cmath&gt;::中什么都没介绍; 所有功能都在std:: 中。实际上,只有 export 不太受尊重,不同的编译器做得很 不同的东西。如果包含&lt;cmath&gt;,则使用std:: 到处都是,或者你得到的东西因编译器而异。

  • C 没有提供任何重载:abs 采用了 int,并且是 在&lt;stdlib.h&gt;fabs 中声明了double,并且是 在&lt;math.h&gt; 中声明。

  • 如果您在 C++ 中包含 &lt;math.h&gt;,则不清楚您的 得到了,但由于似乎没有一个实施者关心 无论如何都是标准(参见上面的第一点)......

粗略地说,要么你包含&lt;cmath&gt;,并且前缀 std:: 的所有用途,或者您包括 &lt;math.h&gt;,以及 如果您想要支持浮点(以及 除intdouble 之外的类型的各种后缀)。

C++11 和 C11 增加了一些新的变化:

  • &lt;cmath&gt; 现在允许(但不是必需)引入 :: 中的符号也是如此。还有一件事可能会有所不同 取决于实施。 (这里的目标是使 符合现有实现。)

  • C 有一个新头文件 &lt;tgmath.h&gt;,它使用编译器魔法 使&lt;math.h&gt; 中的函数表现得好像它们是 在 C++ 中重载。 (所以它不适用于abs,但仅适用于 到fabs。)这个头文件没有被添加到C++中,因为 C++ 不需要任何编译器魔法的明显原因 这个。

总而言之,情况变得稍微糟糕了,我的 上述建议仍然有效。包括&lt;math.h&gt;&lt;stdlib.h&gt;,并使用 abs/fabs 及其派生词(例如 labsfabsf 等)排他地,或包括 &lt;cmath&gt;,和 仅使用std::abs。其他任何事情,你都会遇到 便携性问题。

【讨论】:

  • 你是对的,这是一团糟 :-) 但是非常感谢你的详细回答和对 C/C++ 历史的描述
  • 优秀的答案。一个证实了我在调试后发现为什么在计算非常相似角度之间差异的 Visual Studio 编译应用程序上完美运行的代码是有效的,但是当代码被移植到 linux/gcc 时,答案突然改变了。从类设计的 c++ 角度来看(并忽略向后兼容性问题),您获得 abs( x) 的期望真的会让您感到痛苦,因为这一切都有效,直到突然它不起作用。所以为了安全起见,您需要明确说明您想要哪一个: abs() fabs() 或 std::abs()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-02-02
  • 2012-11-07
  • 2013-04-12
  • 2012-07-05
  • 1970-01-01
  • 2011-03-08
  • 1970-01-01
相关资源
最近更新 更多