【问题标题】:Avoiding compiler issues with abs()使用 abs() 避免编译器问题
【发布时间】:2012-01-30 15:41:08
【问题描述】:

当在 g++ 4.6.1 中使用 std::abs() 函数的 double 变体而没有 std 时,不会给出警告或错误。

#include <algorithm>
#include <cmath>

double foobar(double a)
{
     return abs(a);
}

这个版本的 g++ 似乎通过来自algorithm 的包含之一将abs()double 变体拉入全局命名空间。这看起来现在是标准允许的(参见question),但不是必需的。

如果我使用编译器编译上面的代码,没有将abs()double变体拉入全局命名空间(比如g++ 4.2),那么会报如下错误:

warning: passing 'double' for argument 1 to 'int abs(int)'

如何强制 g++ 4.6.1 和其他将函数拉入全局命名空间的编译器发出警告,以便在与其他编译器一起使用时防止错误?

【问题讨论】:

  • 如果这是您需要的功能,使用std::abs 有什么问题?
  • @JonathanLeffler 没什么,但很容易被错误地错过。我不希望该漏洞未被发现并导致其他编译器出现编译问题。

标签: c++


【解决方案1】:

你使用的函数实际上是abs的整数版本,GCC会隐式转换为整数。

这可以通过一个简单的测试程序来验证:

#include <iostream>
#include <cmath>

int main()
{
    double a = -5.4321;
    double b = std::abs(a);
    double c = abs(a);

    std::cout << "a = " << a << ", b = " << b << ", c = " << c << '\n';
}

输出是:

a = -5.4321,b = 5.4321,c = 5

要获得关于此的警告,请在 g++ 中使用 -Wconversion 标志。实际上,该选项的 GCC 文档明确提到当参数是 double 时调用 abs。所有警告选项都可以在here找到。

【讨论】:

  • @SamDeHaan 抱歉,更新结果但忘记更新代码。 :)
  • 是标准发生了变化,还是 g++ 的实现发生了变化,导致了 4.6.1 而不是 4.2 的隐式转换?两者都有效吗?
  • 上面的代码不能用我的 g++ (4.4.2) 版本编译。但是,如果我添加一个 #include &lt;math.h&gt; 它会。 VC++(VS 2010)调用abs的双重版本。 (我认为这实际上是原始帖子的重点。行为非常多样。)形式上,它不应该在 C++03 中编译;它是否在 C++11 中编译是实现定义的。然而,在实践中,实现之间总是存在很大差异。
【解决方案2】:

请注意,您不需要明确地#include &lt;cmath&gt;&lt;iostream&gt; 也会造成损害(可能还有其他一些标头)。另外,请注意-Wall 不会给您任何警告。

#include <iostream>

int main() {
  std::cout << abs(.5) << std::endl;
  std::cout << typeid(decltype(abs)).name() << std::endl;
}

给出输出

0
FiiE

开启

gcc version 7.4.0 (Ubuntu 7.4.0-1ubuntu1~18.04) 

【讨论】:

    猜你喜欢
    • 2013-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-08
    相关资源
    最近更新 更多