【问题标题】:Strange bug in usage of abs() I encountered recently我最近遇到的 abs() 使用中的奇怪错误
【发布时间】:2011-11-28 16:41:00
【问题描述】:

我有我构建的 C++/C 混合代码

a) Win-7 x32 上的 Visual C++ 2010 Express(免费版)。

b) 安装在 Windows-7 Home 高级版 x32 上的 Cygwin/Gcc 环境。 gcc 3.4.4 版本(cygming special, gdc 0.12, using dmd 0.125)

c) Ubuntu 10.04 Linux-GCC 版本 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

我有一个代码如下(它是我的用户定义类的成员函数),它计算传递的对象 myhalf-的绝对值-

myhalf::myhalfabs(myhalf a)
{
    float tmp;   
    tmp = abs(a.value); //This abs is from math.h :-  float abs(float)
    return tmp;
}

这在 MS - Visual C++ 2010 中可以正常工作。 -ve nos 的 abs() 正确返回为具有相同值的 +ve nos。 奇怪的是,当我在上面提到的 b) Cygwin/gcc 环境和 c) Linux-gcc 4.4.3 上构建此代码时,我得到了垃圾输出。所以启动了 gdb,经过大量的汗水和对代码的“二进制搜索方法”以确定它开始出错的地方,我点击了这段代码,如上所示:

tmp = abs(a.value);

在 cygwin/gcc 下表现异常。

对于 -ve 数字 abs() 返回 0(零)。什么鬼??

然后作为一种解决方法,避免从 stdlib 调用 abs(),并将我自己的 abs 编码如下:

myhalf::myhalfabs(myhalf a)
{
    float tmp;
    unsigned int tmp_dbg;
    // tmp = abs(a.value);
    tmp_dbg = *(unsigned int*)(&a.value);
    tmp_dbg = tmp_dbg & 0x7FFFFFFF;
    tmp = *(float*)(&tmp_dbg);

    return tmp;
}

这在 cygwin/gcc 和 linux-gcc 上运行良好,并且输出符合预期,当然它在 MS-Visual C++ 2010 上运行良好。

这是我使用的 cygwin/gcc 和 linux-gcc 构建的整个 Makefile。只是如果有人怀疑那里有什么可疑之处:-

OBJS= <all my obj files listed here explicitly>

HEADERS= <my header files here>
CFLAGS= -Wall
LIBS= -lm
LDFLAGS= $(LIBS)

#MDEBUG=1
ifdef MDEBUG
CFLAGS += -fmudflap
LDFLAGS += -fmudflap -lmudflap
endif

myexe:    $(OBJS)
    g++ $(OBJS) $(LDFLAGS) -o myexe

%.o:    %.cpp $(HEADERS) Makefile
    g++ $(CFLAGS) -c $<

clean:
    rm -f myexe $(OBJS)

1] 这里发生了什么?这个奇怪的错误的根本原因是什么?

2] 我是否在 cygwin 上使用了一些旧版本的 gcc,它存在已知错误或其他问题?

3] 这个函数 float abs(float) 是否已被弃用或被新版本取代?

任何指针都是有用的。

【问题讨论】:

  • 如果你创建一个小测试用例会很有用,这样每个人都可以拿sn-p,不加修改地编译,自己看看你的意思。
  • abs() 函数通常返回一个int,您将它分配给float。你确定这不是你问题的根源吗?
  • 你和fabs有同样的行为吗?
  • 我同意 larsks - 有一个 fabs() 函数专门用于浮动。改用它有帮助吗?
  • @littleadv - 将在周一尝试晶圆厂。会更新。 larsks - 见 math.h 。 abs 可以接受 float return float。

标签: c++ standard-library


【解决方案1】:

math.h 具有 abs 的 C 版本,它在 ints 上运行。对于 C++ 重载使用 &lt;cmath&gt;,对于 C 浮点版本使用 fabs()

【讨论】:

  • 是的,我看到我包含了 math.h(不推荐用于在 C++ 代码中包含 C 库,我的错)将尝试 cmath.h 或 cstdlib,同样建议 Mark.B
  • @goldenmean:cmath,而不是 cmath.h。标准 c++ 头文件没有扩展名
  • @PlasmaHH - 是的,对不起。它的 .
【解决方案2】:

首先,abs() 接受并返回一个int。您应该使用fabs(),它接受并返回一个浮点值。

现在,您最终调用的 abs() 实际上是一个 GCC built-in function,它返回一个 int,但显然接受 float 参数并在这种情况下返回 0

【讨论】:

  • 它实际上会将float 转换为int 并截断该值。也就是说 0.001 被截断为 0,1.001 被截断为 1,等等。
【解决方案3】:

几乎可以肯定的是,在您的 MSVC 案例中,它正在拾取 C++ abs 浮点重载(可能由于某种原因被带入全局命名空间)。然后在 g++ 中,它没有选择 C++ 版本(它没有隐式导入到全局命名空间中),而是 C 版本可以运行并返回 int,然后将输出截断为零。

如果您 #include &lt;cmath&gt; 并使用 std::abs 它应该可以在您的所有平台上正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-03
    • 2012-02-20
    • 1970-01-01
    • 1970-01-01
    • 2021-11-29
    • 2021-11-10
    • 1970-01-01
    相关资源
    最近更新 更多