31

当心,我说的是::abs(),不是std::abs()

根据cplusplus.com 网站, h C 版本abs的行为应该不同stdlib.,如果你包括<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.h或。cmath
  • 程序输出为:x=-1.5 ax=1

最后是Linux下的结果:

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

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

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

1 回答 1

43

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

  • 正式,包括<cmath>::; 所有的功能都在std::. 实际上,only export不太受尊重,不同的编译器做了非常不同的事情。如果您包含<cmath>,则您std:: 在任何地方都使用过,或者您得到的内容因编译器而异。

  • C 没有提供任何重载:abs接受一个int,并在中声明<stdlib.h>fabs接受double,并在中声明<math.h>

  • 如果您包含<math.h>在 C++ 中,则不清楚您得到了什么,但因为无论如何实施者似乎都不关心标准(参见上面的第一点)......

粗略地说,要么包含<cmath>, 并在所有使用前加上前缀,要么std::包含<math.h>, 并fabs在您想要支持浮点(以及除intor之外的类型的各种后缀double)时使用。

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

  • <cmath>现在也允许(但不是必须)引入符号::。另一件事可能会因实施而异。(这里的目标是使现有的实现符合标准。)

  • C 有一个新的头文件 ,<tgmath.h>它使用编译器魔法使函数<math.h>表现得就像在 C++ 中一样被重载。(所以它不适用于abs,而仅适用于fabs。)这个头文件没有被添加到 C++ 中,原因很明显,C++ 不需要任何编译器魔法。

总而言之,情况变得更糟了,我上面的建议仍然成立。包括<math.h><stdlib.h>,并且排他地使用abs/fabs和它们的派生词(例如 labsfabsf等),或者包括<cmath>,并且std::abs排他地使用。其他任何事情,您都会遇到可移植性问题。

于 2014-01-27T22:37:34.497 回答