【发布时间】:2014-02-18 23:40:06
【问题描述】:
注意,我说的是::abs(),而不是std::abs()
根据cplusplus.com website,abs 的行为应该与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.h和stdlib.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 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 标准中没有
<cstdlib>。说“在 C 中,abs 只在中声明”是错误的。 -
我会知道 cplusplus.com 的资源不够精确,谢谢!
-
“处理
::abs,而不是std::abs” – 呃,你是怎么知道的?