Подтвердить что ты не робот

Странная ошибка в использовании abs(), с которой я столкнулся недавно

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

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

b) Окружение Cygwin/Gcc, установленное в версии Premium версии Windows 7 Home. Версия gcc версии 3.4.4 (cygming special, 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 С++ 2010. abs() of -ve nos вернулись правильно, так как + ve nos имеют одинаковое значение. Странно, когда я построил этот код на b) среде Cygwin/gcc и c) Linux-gcc 4.4.3, упомянутом выше, я получал нежелательный результат. Так что загорелся gdb, а после много пота и "двоичного поиска" в коде, чтобы решить, где он начал идти не так, я ударил этот фрагмент кода, как показано выше:

tmp = abs(a.value);

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

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

Затем, работая, избегал вызова abs() из stdlib и кодировал свой собственный абс, как показано ниже:

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 С++ 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] Известно ли, что эта функция float abs (float) устарела или что-то с более новой версией заменяет ее?

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

4b9b3361

Ответ 1

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

Ответ 2

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

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

Ответ 3

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

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