Question Bug étrange dans l'utilisation de abs () j'ai rencontré récemment


J'ai un code mixte C ++ / C sur lequel je construis

a) Visual C ++ 2010 Express (version gratuite) sur Win-7 x32.

b) Environnement Cygwin / Gcc installé sur une édition Windows XP Home Premium x32. La version gcc 3.4.4 (cygming special, gdc 0.12, utilisant dmd 0.125)

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

J'ai un code comme ci-dessous (c'est une fonction membre pour ma classe définie par l'utilisateur) qui calcule la valeur absolue de l'objet passé myhalf-

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

Cela fonctionne parfaitement comme souhaité dans MS - Visual C ++ 2010. abs () de -ve nos ont été renvoyés correctement comme + ve ayant la même valeur. Curieusement, quand j'ai construit ce code sur b) environnement Cygwin / gcc & c) Linux-gcc 4.4.3 mentionné ci-dessus, j'obtenais des résultats indésirables. Donc, gdb allumé, et après beaucoup de sueur et «approche de recherche binaire» sur le code pour décider où il a commencé à mal tourner, je frappe ce morceau de code comme indiqué ci-dessus:

tmp = abs(a.value);

qui se comportait étrangement sous cygwin / gcc.

Pour -ve nombre abs () renvoyait 0 (zéro). WTF ??

Ensuite, en évitant d'appeler abs () de stdlib, et de coder mes propres abs comme ci-dessous:

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

Cela a bien fonctionné sur cygwin / gcc et linux-gcc et la sortie était comme vous le souhaitez, et bien sûr, cela a bien fonctionné sur MS-Visual C ++ 2010.

C'est le Makefile complet pour les versions cygwin / gcc et linux-gcc, j'utilise. Si quelqu'un soupçonne quelque chose de louche: -

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] Que se passe-t-il ici? Quelle est la cause fondamentale de cet étrange bug?

2] Est-ce que j'utilise une ancienne version de gcc sur cygwin qui a ce problème en tant que bogue connu?

3] Cette fonction float abs (float) est-elle connue pour être obsolète ou quelque chose avec une version plus récente qui la remplace?

Les pointeurs sont utiles.


19
2017-09-30 18:26


origine


Réponses:


math.h a la version C de abs qui fonctionne sur ints. Utilisation <cmath> pour les surcharges C ++ ou l'utilisation fabs() pour la version en virgule flottante C


28
2017-09-30 18:41



Premier, abdos() prend et renvoie un int. Tu devrais utiliser fabs (), qui prend et renvoie une valeur à virgule flottante.

Maintenant le abs() vous finissez par appeler est en fait un GCC fonction intégrée, qui renvoie un int, mais accepte apparemment un float argument et retours 0 dans ce cas.


11
2017-09-30 18:40



Presque certainement ce qui se passe, c'est que dans votre cas MSVC, il prend le C ++ abs float overload (qui est probablement amené dans l'espace de noms global pour une raison ou une autre). Et puis, dans g ++, il ne prend PAS la version C ++ (qui n’est pas implicitement importée dans l’espace de noms global) mais la version C qui fonctionne et renvoie un int qui tronque alors la sortie à zéro.

Si vous #include <cmath> et utilise std::abs cela devrait fonctionner sur toutes vos plates-formes.


7
2017-09-30 18:41