25

I have C++/C mixed code which I build on

a) Visual C++ 2010 Express(Free version) on Win-7 x32.

b) Cygwin/Gcc environment installed on a Windows-7 Home premium edition x32. The gcc version 3.4.4 (cygming special, gdc 0.12, using dmd 0.125)

c) Ubuntu 10.04 Linux- GCC version 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

I have a code as below(Its a member function for my user defined class) which computes absolute value of the passed object myhalf-

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

This is working perfectly as desired in MS - Visual C++ 2010. abs() of -ve nos were returned correctly as +ve nos having same value. Strangely when I built this code on b) Cygwin/gcc environment & c) Linux-gcc 4.4.3 mentioned above, I was getting junk output. So fired up gdb, and after lot of sweat and 'binary-search approach' on the code to decide where it started going wrong, I hit this piece of code as shown above :

tmp = abs(a.value);

which was behaving strangely under cygwin/gcc.

For -ve numbers abs() was returning 0(zero). WTF??

Then as a work around, avoided calling abs() from stdlib, and coded my own abs as below:

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;
}

This worked fine on cygwin/gcc & linux-gcc and output was as desired, And of course it worked fine on MS-Visual C++ 2010.

This is the whole Makefile for the cygwin/gcc and linux-gcc builds, I use. Just if anyone supspects something fishy there:-

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] What is going on here? What is the root cause of this strange bug?

2] Am i using some old version of gcc on cygwin which has this issue as known bug or something?

3] Is this function float abs(float) known to be deprecated or something with a newer version superseding it?

Any pointers are useful.

goldenmean
  • 18,376
  • 54
  • 154
  • 211
  • 2
    It would be useful if you created a small testcase, so that everyone can take the snippet, compile unmodified, and see for himself what you mean. – PlasmaHH Sep 30 '11 at 18:35
  • 4
    The `abs()` function generally returns an `int`, and you're assigning it to a `float`. Are you sure this isn't the root of your problems? – larsks Sep 30 '11 at 18:35
  • 1
    do you get the same behavior with `fabs`? – littleadv Sep 30 '11 at 18:38
  • 1
    I agree with larsks - there's a `fabs()` function specifically for floats. Does it help to use that instead? – Xavier Holt Sep 30 '11 at 18:41
  • @littleadv - Will try with fabs on Monday. Will update. larsks - see math.h . abs has can faccept float return float. – goldenmean Sep 30 '11 at 18:42

3 Answers3

32

math.h has the C version of abs which operates on ints. Use <cmath> for the C++ overloads or use fabs() for the C floating point version.

Dave Rager
  • 8,002
  • 3
  • 33
  • 52
15

First, abs() takes and returns an int. You should use fabs(), which takes and returns a floating-point value.

Now, the abs() you're ending up calling is actually a GCC built-in function, which returns an int, but apparently accepts a float argument and returns 0 in that case.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • 3
    It will actually cast the `float` to an `int` and truncate the value. That is 0.001 gets truncated to 0, 1.001 gets truncated to 1, etc. – Zac Howland Aug 16 '13 at 19:50
11

Almost certainly what's happening is that in your MSVC case it's picking up the C++ abs float overload (which is probably being brought into the global namespace for some reason or other). And then in g++ it's NOT picking up the C++ version (which isn't implicitly imported into the global namespace) but the C version that works on and returns an int which is then truncating the output to zero.

If you #include <cmath> and use std::abs it should work fine on all your platforms.

Mark B
  • 95,107
  • 10
  • 109
  • 188