67

我有以下 C++ 代码:

#include <math.h>
#include <cmath.h>      // per http://www.cplusplus.com/reference/clibrary/cmath/abs/

// snip ...

if ( (loan_balance < 0) && (abs(loan_balance) > loan_payment) ) {
    ...
}

make炸毁:

error: call of overloaded 'abs(double)' is ambiguous

也很有趣:

/usr/include/stdlib.h:785: note: candidates are: int abs(int)

如何指定编译器需要调用 cmath.h 中可以处理浮点数的 abs()?

编译器信息(不确定这是否重要):

[some_man@some_box ~/some_code]#  gcc -v
Using built-in specs.
Target: i386-redhat-linux
Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr    /share/info --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada --enable-java-awt=gtk --disable-dssi --enable-plugin --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre --with-cpu=generic --host=i386-redhat-linux
Thread model: posix
gcc version 4.1.2 20080704 (Red Hat 4.1.2-44)
4

4 回答 4

55

标头<math.h>是 C 标准库标头。它在全局命名空间中定义了很多东西。标头<cmath>是该标头的 C++ 版本。它在 namespace 中定义了基本相同的东西std。(有一些区别,比如 C++ 版本带有一些函数的重载,但这没关系。)头文件<cmath.h>不存在。

由于供应商不想维护本质上相同的标头的两个版本,因此他们提出了不同的可能性,即只在幕后使用其中一个。通常,这是 C 头文件(因为 C++ 编译器能够解析它,而相反的则不起作用),而 C++ 头文件只包含它并将所有内容拉入 namespace std。或者有一些宏魔法来解析相同的标头,无论是否namespace std围绕它。除此之外,在某些环境中,如果标头没有文件扩展名(例如编辑器无法突出显示代码等),这会很尴尬。所以一些供应商会<cmath>是一个单行的,包括一些其他带有.h扩展名的标题。或者有些人会将所有包含匹配的内容映射<cblah><blah.h>(通过宏魔术,在__cplusplus定义时成为 C++ 头文件,否则成为 C 头文件)<cblah.h>或其他。

这就是为什么在某些平台上<cmath.h>,包括不应该存在的 .

我不知道您使用哪个标准库实现。我想这是 GCC 附带的,但我不知道,所以我无法准确解释你的情况发生了什么。但这肯定是上述供应商特定黑客之一的混合,并且您包含了一个您不应该包含自己的标题。也许它是<cmath>映射到<cmath.h>您尚未定义的特定(一组)宏的地方,因此您最终得到了两个定义。

但是请注意,这段代码仍然不应该编译:

#include <cmath>

double f(double d)
{
  return abs(d);
}

abs()全局命名空间中不应该有 a (它是std::abs())。但是,根据上述实现技巧,很可能会有。稍后移植此类代码(或者只是尝试使用供应商的下一个不允许这样做的版本来编译它)可能非常乏味,因此您应该密切关注这一点。

于 2009-09-03T16:04:07.423 回答
42

它归结为:math.h来自C并创建于 10 多年前。在 math.h 中,由于其原始性质,该abs()函数“本质上”仅适用于整数类型,如果您想获得 double 的绝对值,则必须使用fabs(). 当创建 C++ 时,它采用math.h并制作了它cmathcmath本质上是 math.h,但针对 C++ 进行了改进。它改进了诸如必须区分fabs()和 abs 之类的东西,并且仅abs()适用于双精度和整数类型。总而言之:使用 math.h 并abs()用于整数、fabs()双精度数或使用 cmath 并且只对所有内容使用 abs(更简单且推荐)

希望这可以帮助任何遇到同样问题的人!

于 2011-03-27T16:26:58.013 回答
19

使用 fabs() 而不是 abs(),它是相同的,但用于浮点数而不是整数。

于 2011-09-14T11:00:50.300 回答
3

在我的情况下,我在使用labs()而不是abs().

于 2019-09-22T08:24:38.090 回答