我最近在使用abs()时遇到了一个奇怪的bug

Strange bug in usage of abs() I encountered recently

本文关键字:一个 bug 最近 abs 遇到      更新时间:2023-10-16

我有c++/C混合代码,我建立在

a) Visual c++ 2010 Express(免费版)在Win-7 x32.

b) Cygwin/Gcc环境安装在Windows-7家庭高级版x32。gcc版本3.4.4 (cygming special, gdc 0.12,使用dmd 0.125)

c) Ubuntu 10.04 Linux- GCC version 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中完美地工作。Abs()被正确地返回为具有相同值的+ve no。奇怪的是,当我在b) Cygwin/gcc环境&c)上面提到的Linux-gcc 4.4.3,我得到的是垃圾输出。于是,我启动了gdb,在对代码进行了大量的努力和"二进制搜索方法"以确定它开始出错的地方之后,我点击了如上所示的这段代码:

tmp = abs(a.value);

在cygwin/gcc下表现异常。

For -ve numbers abs()返回0(零)。WTF ? ?

然后作为一个工作,避免从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]这是怎么回事?这个奇怪bug的根本原因是什么?

2]我是否在cygwin上使用了一些旧版本的gcc,其中有这个问题作为已知的错误或其他什么?

3]此函数float abs(float)已知已弃用或有新版本取代它吗?

math.h具有abs的C版本,该版本对int s进行操作。对于c++的重载使用<cmath>,对于C的浮点版本使用fabs()

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

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

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

如果你使用#include <cmath>std::abs,它应该在你所有的平台上工作得很好。