Strange bug in usage of abs() I encountered recently
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.
math.h
has the C version of abs
which operates on int
s. Use <cmath>
for the C++ overloads or use fabs()
for the C floating point version.
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.
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.
精彩评论