2011-09-30 16 views
18

tengo C++/C de código mixto que construyo enfallo extraño en el uso de abs() me encontré recientemente

a) Visual C++ 2010 Express (versión libre) en Win-7 x32.

b) Entorno Cygwin/Gcc instalado en Windows-7 Home premium edition x32. La versión gcc 3.4.4 (cygming especial, gdc 0,12, utilizando DMD 0.125)

c) Ubuntu 10.04 versión en Linux GCC 4.4.3 (Ubuntu 4.4.3-4ubuntu5)

Tengo un código como abajo (Su una función miembro para mi clase definida por el usuario), que calcula el valor absoluto de la objeto pasado myhalf-

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

esto está funcionando perfectamente como se desea en MS - fueron devueltos Visual C++ 2010. abs() de los números -ve correctamente como + ve nos tiene el mismo valor. Extrañamente cuando construí este código en b) Entorno Cygwin/gcc & c) Linux-gcc 4.4.3 mencionado anteriormente, obtenía salida de basura. Así que puso en marcha el BGF, y después de mucho sudor y 'enfoque binario de búsqueda' en el código para decidir donde empezó a ir mal, llegué a este pedazo de código de la imágen:

tmp = abs(a.value); 

que se comporta de forma extraña bajo cygwin/gcc.

Para -ve números abs() devolvió 0 (cero). ¿WTF?

Entonces, como un trabajo alrededor, evitó llamar abs() desde stdlib, y codificados mi propia abs de la siguiente manera:

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

Esto funcionó muy bien en cygwin/gcc & fue como se desee linux-gcc y de salida, Y, por supuesto, funcionó bien en MS-Visual C++ 2010.

Este es el Makefile completo para las compilaciones cygwin/gcc y linux-gcc, que uso. Sólo si alguien supspects algo raro ahí: -

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] Lo que está pasando aquí? ¿Cuál es la causa raíz de este extraño error?

2] ¿Estoy usando alguna versión anterior de gcc en cygwin que tiene este problema como un error conocido o algo así?

3] ¿Se desconoce esta función float abs (float) o algo con una versión más nueva que lo reemplaza?

Cualquier puntero es útil.

+2

Sería útil crear una pequeña caja de prueba para que todos puedan tomar el fragmento, compilar sin modificaciones y ver por sí mismo lo que quiere decir. – PlasmaHH

+4

La función 'abs()' generalmente devuelve un 'int', y lo está asignando a un' float'. ¿Estás seguro de que esta no es la raíz de tus problemas? – larsks

+1

¿obtienes el mismo comportamiento con 'fabs'? – littleadv

Respuesta

27

math.h tiene la versión C de abs que funciona en int s. Use <cmath> para las sobrecargas de C++ o use fabs() para la versión en coma flotante C.

+1

Sí, veo que estoy incluyendo math.h (uso obsoleto para incluir bibliotecas C en código C++, mi mal) Se probará cmath.h o cstdlib, como también sugirió Mark.B – goldenmean

+3

@goldenmean: cmath, not cmath.h. los encabezados estándar de C++ no tienen extensión – PlasmaHH

+0

@PlasmaHH - Yean, lo siento. Es . – goldenmean

11

Primero, abs() toma y devuelve int. Debe usar fabs(), que toma y devuelve un valor de coma flotante.

Ahora, el abs() que está terminando la llamada es en realidad un GCC built-in function, que devuelve una int, pero al parecer acepta un argumento y devuelve float0 en ese caso.

+1

Realmente convertirá el 'float' en un' int' y truncará el valor. Eso es 0.001 se trunca a 0, 1.001 se trunca a 1, etc. –

7

Casi con certeza, lo que está sucediendo es que en su caso de MSVC está recogiendo la sobrecarga del flotador C++ abs (que probablemente se está llevando al espacio de nombres global por alguna razón u otra). Y luego en g ++ NO está recogiendo la versión de C++ (que no se importa implícitamente en el espacio de nombres global) sino la versión C que funciona y devuelve un int que luego trunca el resultado a cero.

Si #include <cmath> y usa std::abs debería funcionar bien en todas sus plataformas.

Cuestiones relacionadas