45 votes

log (10.0) peut compiler mais log (0.0) ne le peut pas?

Pour la suite C code source:

#include <math.h>

int main(void)
{
    double          x;

    x = log(0.0);

    return 0;
}

Quand je compile avec gcc -lm, j'ai eu:

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

Mais, si je le remplace log(0.0) avec log(10.0), alors il peut compiler avec succès.

Je ne comprends pas très bien ce, depuis n'importe qu'ils font sens mathématique ou non, ils doivent rédiger -- il n'y a pas d'erreur de syntaxe. Quelqu'un pourrait-il m'expliquer cela?

Juste au cas où, mon gcc -v sortie:

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)

59voto

Shafik Yaghmour Points 42198

gcc pouvez utiliser les fonctions internes dans de nombreux cas, leur documentation dit:

La plupart de ces fonctions ne sont optimisées dans certains cas; si elles ne sont pas optimisés dans un cas particulier, un appel à une fonction de la bibliothèque est émise.

donc, par conséquent, gcc n'aurez pas besoin de lien en face de la bibliothèque de mathématiques lors de l'utilisation de la fonction builtin mais depuis log(0) est pas défini , il probablement forces de l'gcc de l'évaluer au moment de l'exécution, car il a un effet secondaire.

Si l'on regarde le projet de standard C99 section 7.12.1 Traitement de conditions d'erreur dans le paragraphe 4 il est dit (c'est moi qui souligne):

Flottant, conséquence des débordements si l'ampleur de la mathématique le résultat est fini mais si grande que le résultat mathématique ne peut pas être représentés sans l'extraordinaire, l'erreur d'arrondi dans un objet de la type spécifié. Si un flottant entraîner des débordements et arrondi par défaut est en effet, ou si le résultat mathématique est exactement l'infini de finis les arguments (pour un exemple de log(0.0)), alors la fonction renvoie la la valeur de la macro HUGE_VAL, HUGE_VALF ou HUGE_VALL, selon le le type de retour, avec le même signe que la valeur correcte de la fonction; si l'expression entière math_errhandling & MATH_ERRNO est différente de zéro, l'expression entière errno acquiert la valeur ERANGE; si l'entier expression math_errhandling & MATH_ERREXCEPT est différent de zéro, le ‘division par zéro" floating point exception est levée si l' résultat mathématique est exactement l'infini et le ‘dépassement" exception de virgule flottante est élevé autrement.

Nous pouvons voir un exemple d'utilisation de -S drapeau pour générer de l'assemblée et de l' grep log de filtrer les appels d' log.

Dans le cas d' log(0.0) l'instruction suivante est générée (voir en direct):

call    log

mais dans le cas d' log(10.0) n call log instruction est générée, (voir en direct).

On peut généralement prévenir gcc d'utiliser builtin fonction à l'aide de l' -fno-builtin drapeau qui est probablement un moyen plus rapide pour tester si une fonction est utilisée.

Notez que -lm besoin d'aller après le fichier source, par exemple (pris à partir lié réponse) si main.c requis à la bibliothèque de mathématiques alors vous devez utiliser:

 gcc main.c -lm 

8voto

Axel Points 6352

La compilation est bien, c'est juste l'éditeur de liens commutateur -lm qui est manquant.

La deuxième version, probablement, les compile et les liens car gcc remplace log(10.0) avec une constante, donc pas d'appel à la bibliothèque de mathématiques est nécessaire. Dans le second cas, le résultat est mathématiquement pas défini, et les résultats de l'évaluation dans un domaine d'erreur. Dans ce cas, l'expression ne peut pas être remplacé par une constante, depuis la manipulation des erreurs de domaine peut être différent au moment de l'exécution.

Citation de la C-standard (projet):

Sur un domaine d'erreur, la fonction renvoie une mise en œuvre définies par l' valeur; si l'expression entière math_errhandling & MATH_ERRNO est différent de zéro, l'expression entière errno acquiert la valeur d'EDOM; si le expression entière math_errhandling & MATH_ERREXCEPT est différent de zéro, le ‘non valide" floating point exception est levée.

L'évaluation de l' log(0.0) , soit des résultats dans le retour de la valeur HUGE_VAL (pas NAN comme je l'ai demandé avant) ou une exception de virgule flottante.

EDIT: j'ai corrigé ma réponse sur la base des commentaires reçus et ajouté un lien vers la description dans le C standard.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X