我最近遇到的使用abs()的奇怪错误
我有 C++/C 混合代码,它是
在 Win-7 x32 上的 a) Visual C++ 2010 Express(免费版)上构建的。
b) 安装在 Windows-7 Home premium Edition x32 上的 Cygwin/Gcc 环境。 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. -ve nos 的abs() 正确返回为具有相同值的+ve nos。 奇怪的是,当我在 b) Cygwin/gcc 环境 & 上构建此代码时c) 上面提到的 Linux-gcc 4.4.3,我得到了垃圾输出。因此启动了 gdb,经过大量的汗水和代码上的“二进制搜索方法”来确定它开始出错的地方,我点击了如上所示的这段代码:
tmp = abs(a.value);
它在 cygwin/gcc 下表现得很奇怪。
对于 -ve 个数字,abs() 返回 0(零)。搞什么??
然后作为解决方法,避免从 stdlib 调用abs(),并编写我自己的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 和 cygwin/gcc 上运行良好; linux-gcc 和输出是根据需要的,当然它在 MS-Visual C++ 2010 上工作得很好。
这是我使用的 cygwin/gcc 和 linux-gcc 构建的整个 Makefile。如果有人怀疑那里有可疑之处:-
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] 我是否在 cygwin 上使用某些旧版本的 gcc,该版本存在已知错误或其他问题?
3] 这个函数 float abs(float) 是否已知已被弃用或有新版本取代它?
任何指针都是有用的。
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 lt;
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,abs() 接受并返回一个
int
。您应该使用 fabs(),它接受并返回一个浮点值。现在,您最终调用的
abs()
实际上是 GCC 内置的函数,它返回一个int
,但显然接受一个float
参数并在这种情况下返回0
。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 anint
, but apparently accepts afloat
argument and returns0
in that case.几乎可以肯定,在您的 MSVC 案例中,它正在获取 C++
abs
浮点重载(可能由于某种原因被带入全局命名空间)。然后在 g++ 中,它不会获取 C++ 版本(它不会隐式导入到全局命名空间中),而是会运行并返回一个int
的 C 版本,然后将输出截断为零。如果您
#include
并使用std::abs
,它应该可以在您的所有平台上正常工作。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 anint
which is then truncating the output to zero.If you
#include <cmath>
and usestd::abs
it should work fine on all your platforms.math.h
具有 C 版本的abs
,它在int
上运行。对于 C++ 重载使用
或对于 C 浮点版本使用fabs()
。math.h
has the C version ofabs
which operates onint
s. Use<cmath>
for the C++ overloads or usefabs()
for the C floating point version.