日志(10.0)可以编译,但日志(0.0)不能? [英] log(10.0) can compile but log(0.0) cannot?

查看:160
本文介绍了日志(10.0)可以编译,但日志(0.0)不能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有关以下的 C 的源$ C ​​$ C:

 的#include<&math.h中GT;INT主要(无效)
{
    双X;    X =日志(0.0);    返回0;
}

当我编译 gcc的-lm ,我得到了:

  /tmp/ccxxANVH.o:在函数'主':
。交流转换器:(文字+ 0xd中):未定义引用'登录'
collect2:错误:LD返回1退出状态

但是,如果我取代日志(0.0)日志(10.0),那么它可以成功编译。

我不明白这一点,因为不管他们做数学意义与否,他们应该编译 - 没有语法错误。谁能解释一下吗?

以防万一,我的的gcc -v 输出:

 配置有:../src/configure -v --with-pkgversion ='Ubuntu的4.8.2-19ubuntu1'--with-bugurl =文件:/// USR /股票/ DOC / GCC-4.8 / README.Bugs --enable-语言= C,C ++,JAVA,走,D,FORTRAN,objc,OBJ-C ++  -  preFIX =的/ usr --program后缀=  - 4.8 --enable-共享--enable连接体集结号--libexecdir = / usr / lib目录--without-包括-gettext的--enable-线程= POSIX --with-GXX-包括-DIR =的/ usr /包括/ C ++ / 4.8 = --libdir / usr / lib目录--enable-NLS --with-SYSROOT = / --enable-clocale = GNU --enable-libstdcxx调试--enable-libstdcxx时间= YES  - 使GNU的唯一对象--disable-libmudflap --enable-插件--with-系统的zlib --disable-浏览器插件--enable-java的AWT = GTK --enable-GTK开罗--with -java家庭= / usr / lib目录/ JVM / JAVA-1.5.0-的gcj-4.8-AMD64 / JRE --enable-java主--with-JVM的根目录= / usr / lib目录/ JVM / JAVA -1.5.0-GCJ-4.8-amd64的--with-JVM-JAR-DIR = / usr / lib目录/ JVM出口/ JAVA-1.5.0-的gcj-4.8-amd64的--with拱目录= AMD64  - -with-ECJ-JAR =的/ usr /股/ JAVA / Eclipse的ecj.jar --enable-objc-GC --enable-multiarch --disable-werror --with拱-32 = i686的--with-ABI = M64 --with-multilib的列表= M32,M64,MX32 --with调=通用--enable-检查=发行--build = x86_64的Linux的GNU的主机= x86_64的Linux的GNU的--target = x86_64的-Linux的GNU
线程模型:POSIX
gcc版本4.8.2(Ubuntu的4.8.2-19ubuntu1)


解决方案

GCC 可以使用的内建函数在很多情况下的,他们的文件说:


  

许多这些功能是在某些情况下,仅进行了优化;如果他们
  在特殊情况下不进行优化,以库函数的调用
  被发射。


因此​​,因此 GCC 使用内建的功能时,将不再需要对数学库链接,但因为日志(0)是没有定义 它可能迫使 GCC 在运行时,以评估它,因为它具有副作用

如果我们看一下草案C99标准部分 7.12.1 处理错误条件的段落中的 4 的它说(的重点煤矿的):


  

一个浮动的结果溢出,如果数学的幅度
  结果是有限的,但如此之大,数学结果不能
  再$ P $不平凡的舍入误差在的对象psented
  指定的类型。如果一个浮动的结果溢出和默认舍入
  在效果,或者如果数学结果是从一个确切的无穷
  有限的参数(例如日志(0.0)),则该函数返回
  根据宏观HUGE_VAL,HUGE_VALF或HUGE_VALL的价值
  返回类型
,用相同的符号功能的正确值;
  如果整型前pression math_errhandling&安培; MATH_ERRNO不为零,
  整前pression错误号获取价值ERANGE;
如果整
  前pression math_errhandling&安培; MATH_ERREXCEPT为非零值,
  ''除以零'浮点异常,如果募集
  数学结果是一个确切的无穷大,'溢出'
  浮点异常其他方式筹措。


我们可以使用 -S 标志产生组装和的grep的日志过滤掉呼叫的活生生的例子见到日志

日志的情况下(0.0)产生下面的指令(看直播 的):

 通话记录

但在日志(10.0)没有通话记录产生指令,(的 <的情况下A HREF =htt​​p://coliru.stacked-crooked.com/a/d920d8447b7416d5>看直播 的)。

我们通常可以prevent GCC 使用内建函数使用的 - FNO,内置标志这可能是测试是否正在使用一个内置一个更快的方法

注意 -lm 所需要的源文件,例如(从链接答案采取的),如果的main.c 所需的数学库,那么你可以使用:

  GCC的main.c -lm

For the following C source code:

#include <math.h>

int main(void)
{
    double          x;

    x = log(0.0);

    return 0;
}

When I compile with gcc -lm, I got:

/tmp/ccxxANVH.o: In function `main':
a.c:(.text+0xd): undefined reference to `log'
collect2: error: ld returned 1 exit status

But, if I replace log(0.0) with log(10.0), then it can compile successfully.

I don't quite understand this, since no matter they make mathematical sense or not, they should compile -- there is no syntax error. Could anyone explain this?

Just in case, my gcc -v output:

Configured with: ../src/configure -v --with-pkgversion='Ubuntu 4.8.2-19ubuntu1' --with-bugurl=file:///usr/share/doc/gcc-4.8/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.8 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.8 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libmudflap --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.8-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.8-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --disable-werror --with-arch-32=i686 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

解决方案

gcc can use builtin functions in many cases, their documentation says:

Many of these functions are only optimized in certain cases; if they are not optimized in a particular case, a call to the library function is emitted.

so therefore gcc will not need to link against the math library when using the builtin function but since log(0) is not defined it probably forcesgcc to evaluate it at run-time since it has a side effect.

If we look at the draft C99 standard section 7.12.1 Treatment of error conditions in paragraph 4 it says (emphasis mine):

A floating result overflows if the magnitude of the mathematical result is finite but so large that the mathematical result cannot be represented without extraordinary roundoff error in an object of the specified type. If a floating result overflows and default rounding is in effect, or if the mathematical result is an exact infinity from finite arguments (for example log(0.0)), then the function returns the value of the macro HUGE_VAL, HUGE_VALF, or HUGE_VALL according to the return type, with the same sign as the correct value of the function; if the integer expression math_errhandling & MATH_ERRNO is nonzero, the integer expression errno acquires the value ERANGE; if the integer expression math_errhandling & MATH_ERREXCEPT is nonzero, the ‘‘divide-by-zero’’ floating-point exception is raised if the mathematical result is an exact infinity and the ‘‘overflow’’ floating-point exception is raised otherwise.

We can see from a live example using -S flag to generate assembly and grep log to filter out calls to log.

In the case of log(0.0) the following instruction is generated (see it live):

call    log

but in the case of log(10.0) no call log instruction is generated, (see it live).

We can usually prevent gcc from using builtin function by using the -fno-builtin flag which is probably a quicker way to test whether a builtin is being used.

Note that -lm needs to go after the source file, for example (taken from linked answer) if main.c required the math library then you would use:

 gcc main.c -lm 

这篇关于日志(10.0)可以编译,但日志(0.0)不能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆