不同操作系统下complex.h中出现C语言的意外行为

6

Consider the following code:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
int main()
{
   complex double aaa = INFINITY + 0*I;
   printf("%.f + %.f*I\n", creal(aaa), cimag(aaa));
   complex double bbb = 1.0/aaa;
   printf("%.f + %.f*I\n", creal(bbb), cimag(bbb));
   return EXIT_SUCCESS;
}

使用gcc -std=gnu99 -lm编译时,我期望输出为:

inf + 0*I

0 + 0*I

在Linux上这是正确的(在Scientific Linux 6.8使用gcc 4.4.7,Fedora 23使用gcc 5.3.1,Ubuntu 14.04.5使用gcc 4.8.4测试过)。
然而,在OS X(使用clang-602.0.53的10.11.5版本)上输出为:

inf + 0*I

nan + nan*I

显然clang不符合C99标准(参考N1256,第G.5.1节;严格来说,这只是一种推荐做法,而不是一项标准)。事实上,clang没有定义宏__STDC_IEC_559_COMPLEX__,这个宏在G.1节中被介绍。clang有意这样做吗?更新:经过一些检查,我发现我测试过的几个Linux环境也没有定义这个宏,但是代码仍然可以正确运行。 目前,我用的跨平台支持的解决方法是检查宏。
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <complex.h>
int main()
{
   complex double aaa = INFINITY + 0*I;
   printf("%.f + %.f*I\n", creal(aaa), cimag(aaa));
   complex double bbb = 1.0/aaa;
   #ifndef __STDC_IEC_559_COMPLEX__
   if(isnan(bbb)) 
   { 
      bbb = 0; //or do some trick that has to do with the problem context
   }
   #endif
   printf("%.f + %.f*I\n", creal(bbb), cimag(bbb));

   return EXIT_SUCCESS;
}   

但我不确定它是否稳健。有什么建议吗?

2
根据C标准INFINITY扩展为浮点类型的常量表达式,表示正无穷或无符号无穷,如果有的话;否则会在编译时溢出到一个正的浮点常量。因此,其行为可能在不同平台上不完全相同... - Eugene Sh.
@EugeneSh。1. 在这种情况下,INFINITY 扩展为正无穷,可以通过输出的第一行或者调试器进行检查;2. 这里我使用 INFINITY 只是为了提供一个 MWE(最小可行示例)。你也可以写一些溢出的内容,例如 complex double aaa = 1.0/0.0;,但结论不会改变;3. 如果这个方法不起作用,那真的没有意义,因为我已经测试过 double 类型的替代方案(将所有的 complex double 替换为 double,将函数 crealcimag 去掉等等),它是有效的。 - Leo Fang
@LeoFang 数学上处理的方式和printf()的表示方式可能并不完全相同。也许确定问题究竟是clang还是体系结构的最好方法是使用gcc在OSX上编译它。 - Havenard
@Havenard,确实我不清楚这是由于架构还是编译器引起的。我使用gcc在OS X上进行编译,尽管默认情况下gcc是clang/LLVM。我将尝试使用brew获取真正的gcc。 - Leo Fang
3
这似乎是LLVM/Clang的问题,在更新版本中已得到解决。LLVM/Clang 3.6.2(在clang-602.0.53之后)表现如期,而LLVM/Clang 3.5.2则呈现所述行为。 - kdhp
1
@kdhp,你说得对。在发布之前,我正在测试LLVM 3.6.0(clang-602.0.53),我刚刚在另一台运行OS X 10.10.5的机器上进行了测试,该机器使用LLVM 3.7.0(clang-700.1.81),这给了我正确的结果。你可以发布一个答案,我会接受它。谢谢! - Leo Fang
1个回答

1

你正在使用%f而不是%lf作为双精度浮点数参数,这会导致不可预测的行为,我认为。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接