Странная ошибка в использовании abs (), с которой я недавно столкнулся - PullRequest
23 голосов
/ 30 сентября 2011

У меня есть смешанный код C ++ / C, который я строю на

a) Visual C ++ 2010 Express (бесплатная версия) на Win-7 x32.

b) Среда Cygwin / Gcc установлена ​​наWindows-7 Home Premium Edition x32.Версия gcc 3.4.4 (специальный cygming, gdc 0.12, использующий dmd 0.125)

c) Ubuntu 10.04 Linux - версия GCC 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 nos были возвращены правильно как + ve nos, имеющие то же значение.Странно, когда я строил этот код в б) среде Cygwin / gcc и в) Linux-gcc 4.4.3, упомянутой выше, я получал нежелательный вывод.Так что запустил GDB, и после большого количества пота и «бинарного поиска» в коде, чтобы решить, где он начал работать неправильно, я нажал на этот кусок кода, как показано выше:

tmp = abs(a.value);

, который вел себякак ни странно, в cygwin / gcc.

Для -ve чисел abs () возвращала 0 (ноль).WTF ??

Тогда как обходной путь, я избегал вызова abs () из stdlib и кодировал свой собственный 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.

Это весь Makefile для сборок cygwin / gcc и linux-gcc, который я использую.Просто, если кто-то ожидает что-то подозрительное: -

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] Что здесь происходит?В чем основная причина этой странной ошибки?

2] Использую ли я какую-то старую версию gcc на cygwin, в которой эта проблема известна как ошибка или что-то в этом роде?

3] Эта функция с плавающей точкойabs (float) известен как устаревший или что-то с более новой версией, заменяющей его?

Любые указатели полезны.

Ответы [ 3 ]

31 голосов
/ 30 сентября 2011

math.h имеет версию C abs, которая работает на int с. Используйте <cmath> для перегрузок C ++ или fabs() для версии с плавающей запятой C.

14 голосов
/ 30 сентября 2011

Сначала abs () принимает и возвращает int. Вам следует использовать fabs () , которая принимает и возвращает значение с плавающей запятой.

Теперь, abs(), который вы вызываете, на самом деле является встроенной функцией GCC , которая возвращает int, но, очевидно, принимает аргумент float и возвращает 0 в этом случае.

9 голосов
/ 30 сентября 2011

Почти наверняка происходит то, что в вашем случае MSVC он получает перегрузку с плавающей запятой C ++ abs (которая, возможно, по той или иной причине переносится в глобальное пространство имен).И затем в g ++ он НЕ выбирает версию C ++ (которая неявным образом не импортируется в глобальное пространство имен), а версию C, которая работает и возвращает int, который затем обрезает вывод до нуля.

Если вы #include <cmath> и используете std::abs, он должен нормально работать на всех ваших платформах.

...