IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C Discussion :

problème #include <math.h>


Sujet :

C

  1. #1
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut problème #include <math.h>
    Je deviens fou Depuis hier je n'arrive pas à utiliser une fonction de math.h (floor). J'ai un exemple test.c qui l'utilise et qui fonctionne. Parallèlement, j'ai progressivement réduit mon petit prog problématique dice.c à presque rien, y compris il inclut directement ce dont il a besoin (au lieu de passer par mon toolkit habituel) et n'a même plus de header associé. Ce qui fait qu'au final les 2 exemples sont proches. Mais je n'arrive toujours pas à utiliser floor dans dice.c, et je ne vois pas où est la différence qui l'empêche. Voici:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    // test.c
    #include <stdio.h>
    #include <math.h>
     
    int main () {
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       return 1 ;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    // dice.c
    #include <stdlib.h>
    #include <stdio.h>
    #include <math.h>
    typedef unsigned int uint ;
     
    uint random_ordinal (uint max) {
       const float RANDOM_MAX = (float)(RAND_MAX) + 1 ;
       float random_01 = (float)(rand ()) / RANDOM_MAX ;
       return 1 + (uint)(floor(max * random_01)) ;
    }
     
    int main () {
       printf ("random ordinal max 3 : %d\n", random_ordinal(3)) ;
       return 1 ;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    spir@ospir:~/prog/C/WELLRandom$ gcc -c test.c -o test.o
    spir@ospir:~/prog/C/WELLRandom$ gcc test.o -o test
    spir@ospir:~/prog/C/WELLRandom$ ./test
    floor 1.1 : 1.000000
    spir@ospir:~/prog/C/WELLRandom$ gcc -c dice.c -o dice.o
    spir@ospir:~/prog/C/WELLRandom$ gcc dice.o -o dice
    dice.o: In function `random_ordinal':
    dice.c:(.text+0x4b): undefined reference to `floor'
    collect2: ld returned 1 exit status
    Voilà, je poste ce message au risque de passer pour un imbécile, mais c'est peut-être moins imbécile que de rester coincé pour ne pas passer pour un imbécile... et là, je suis complètement coincé . Ca doit être une idiotie terriblement stupide, dites-moi.

    Merci,
    denis

  2. #2
    Expert confirmé
    Avatar de gerald3d
    Homme Profil pro
    Conducteur de train
    Inscrit en
    Février 2008
    Messages
    2 309
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Conducteur de train
    Secteur : Transports

    Informations forums :
    Inscription : Février 2008
    Messages : 2 309
    Billets dans le blog
    5
    Par défaut
    Il faut ajouter -lm lors du lien pour pouvoir utiliser la bibliothèque math.h il me semble.

    Ensuite pourquoi ca fonctionne dans un cas mais pas dans l'autre, là, je ne saurais te dire...

  3. #3
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Par défaut
    Citation Envoyé par gerald3d Voir le message
    Il faut ajouter -lm lors du lien pour pouvoir utiliser la bibliothèque math.h il me semble.
    pour pouvoir utiliser la biliothèque mathématique, oui.
    Ensuite pourquoi ca fonctionne dans un cas mais pas dans l'autre, là, je ne saurais te dire...
    Parce que dans le premier cas, le code généré n'appelle par floor. La phase d'optimisation du compilateur détecte que le paramètre passé à floor est une constante et donc que le calcul du résultat durant l'exécution est inutile.

  4. #4
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut
    Citation Envoyé par jlliagre Voir le message
    pour pouvoir utiliser la biliothèque mathématique, oui.

    Parce que dans le premier cas, le code généré n'appelle par floor. La phase d'optimisation du compilateur détecte que le paramètre passé à floor est une constante et donc que le calcul du résultat durant l'exécution est inutile.
    D'ac, je vais tester avec -lm...................... ça marche pas (encore):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    spir@ospir:~/prog/C/WELLRandom$ gcc -c dice.c -o dice.o
    spir@ospir:~/prog/C/WELLRandom$ gcc -lm dice.o -o dice
    dice.o: In function `random_ordinal':
    dice.c:(.text+0x37): undefined reference to `floor'
    collect2: ld returned 1 exit status
    Mais maintenant je sais qu'il y a un truc spécial avec math.h (et que je suis pas fou ): je vais chercher sur internet à propos de compiler/lier avec math.h, et à propos de -lm.

    PS: C'est typiquement le genre de truc qui me rend un peu colère, ça: comment un utilisateur est-il sensé savoir ça? D'accord, on peut toujours dire RTFM et tout ça mais; je suis sûr que c'est marqué noir sur blanc... mais où? et encore faut-il deviner que math.h est spécial en quelque chose. Et puis de toute façon lire tous les manuels de tout ce qu'on utilise, à fond, et comprendre et retenir tout le contenu et les implications et leds intéractions et tout ça, c'est pas humain (à mon avis). Si vous voyez ce que je veux dire...
    Heureusement qu'il des listes mail et autres forums: merci!

    Merci encore de votre aide,
    Denis

  5. #5
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut ajouter -lm en ***fin*** de ligne de commande à l'édition de liens
    Voilà, toruvé sur internet, tout est dans le titre:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    spir@ospir:~/prog/C/WELLRandom$ gcc -c dice.c -o dice.o
    spir@ospir:~/prog/C/WELLRandom$ gcc dice.o -o dice -lm
    spir@ospir:~/prog/C/WELLRandom$ "./dice"
    random ordinal max 3 : 3
    PS: J'aimerais bien savoir ce qui justifie ce traitement spécial de math.h, et s'il y en a d'autres come ça (des modules de la lib std, ou d'autres libs). [Alors, je marque pas encore la discussion "résolue" pour 24 h, au cas où certains auraient plus d'infos concrètes, et puis ça servira pê à d'autres.]

    Merci à vous,
    denis

  6. #6
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut
    Citation Envoyé par denispir Voir le message
    PS: J'aimerais bien savoir ce qui justifie ce traitement spécial de math.h, et s'il y en a d'autres come ça (des modules de la lib std, ou d'autres libs). [Alors, je marque pas encore la discussion "résolue" pour 24 h, au cas où certains auraient plus d'infos concrètes, et puis ça servira pê à d'autres.]
    J'apporte déjà des précision, dans la FAQ de comp.lang.c (http://c-faq.com/), j'ai trouvé (chercher question 14.3):
    Q: I'm trying to do some simple trig, and I am #including <math.h>, but the linker keeps complaining that functions like sin and cos are undefined.

    A: Make sure you're actually linking with the math library. For instance, due to a longstanding bug in Unix and Linux systems, you usually need to use an explicit -lm flag, at the end of the command line, when compiling/linking. See also questions 13.25, 13.26, and 14.2.

  7. #7
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Salut,

    un moyen simple de connaître les bibliothèques installées avec la libc est de regarder ce que le package installe (la méthode diffère suivant la distribution).
    Un autre moyen simple :
    * Repérer la libc que tu utilises :
    Tu tapes test.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ~> vi test.c
    ~> cat test.c
    int main()
    {
      return 0;
    }
    Tu en fait un exécutable et tu demandes quels sont les bibliothèques dynamiques qu'il s'attend à trouver :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ~> gcc -o test test.c 
    ~> ldd ./test
            linux-vdso.so.1 =>  (0x000016da4000)
            libc.so.6 => /lib64/libc.so.6 (0x000078d40000)
            /lib64/ld-linux-x86-64.so.2 (0x0000790d0000)
    Déjà sans rien faire de particulier 3 bibliothèques dynamiques ... bon la libc y est (=> par défaut sans que tu le demandes la libc est dans la liste des bibliothèques dynamiquement liées).

    La quête continue :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    ~> ls -l /lib64/libc.so.6 
    lrwxrwxrwx 1 root root 14 Apr  6 02:09 /lib64/libc.so.6 -> libc-2.14.1.so
    La libc est un lien qui pointe vers la version 2.14 de la glibc
    On peut supposer que
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    ~> find /lib64 -type f -name '*-2.14*.so'
    /lib64/libnss_files-2.14.1.so
    /lib64/libnss_nis-2.14.1.so
    /lib64/libdl-2.14.1.so
    /lib64/libresolv-2.14.1.so
    /lib64/libcrypt-2.14.1.so
    /lib64/libnsl-2.14.1.so
    /lib64/libc-2.14.1.so
    /lib64/libnss_compat-2.14.1.so
    /lib64/libnss_nisplus-2.14.1.so
    /lib64/ld-2.14.1.so
    /lib64/libnss_hesiod-2.14.1.so
    /lib64/libnss_dns-2.14.1.so
    /lib64/libanl-2.14.1.so
    /lib64/libcidn-2.14.1.so
    /lib64/libBrokenLocale-2.14.1.so
    /lib64/libutil-2.14.1.so
    /lib64/libm-2.14.1.so
    /lib64/librt-2.14.1.so
    /lib64/libpthread-2.14.1.so
    Donne la liste des bibliothèques dynamiques installées par la libc.

    En checkant avec mon utilitaire de gestion de packages :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    glibc - Standard Shared Libraries (from the GNU C Library)
     
    List of Installed Files:
    ...
    /lib64/ld-2.14.1.so
    /lib64/ld-linux-x86-64.so.2
    /lib64/libBrokenLocale-2.14.1.so
    /lib64/libBrokenLocale.so.1
    /lib64/libSegFault.so
    /lib64/libanl-2.14.1.so
    /lib64/libanl.so.1
    /lib64/libc-2.14.1.so
    /lib64/libc.so.6
    /lib64/libcidn-2.14.1.so
    /lib64/libcidn.so.1
    /lib64/libcrypt-2.14.1.so
    /lib64/libcrypt.so.1
    /lib64/libdl-2.14.1.so
    /lib64/libdl.so.2
    /lib64/libm-2.14.1.so
    /lib64/libm.so.6
    /lib64/libnsl-2.14.1.so
    /lib64/libnsl.so.1
    /lib64/libnss_compat-2.14.1.so
    /lib64/libnss_compat.so.2
    /lib64/libnss_dns-2.14.1.so
    /lib64/libnss_dns.so.2
    /lib64/libnss_files-2.14.1.so
    /lib64/libnss_files.so.2
    /lib64/libnss_hesiod-2.14.1.so
    /lib64/libnss_hesiod.so.2
    /lib64/libnss_nis-2.14.1.so
    /lib64/libnss_nis.so.2
    /lib64/libnss_nisplus-2.14.1.so
    /lib64/libnss_nisplus.so.2
    /lib64/libpthread-2.14.1.so
    /lib64/libpthread.so.0
    /lib64/libresolv-2.14.1.so
    /lib64/libresolv.so.2
    /lib64/librt-2.14.1.so
    /lib64/librt.so.1
    /lib64/libthread_db-1.0.so
    /lib64/libthread_db.so.1
    /lib64/libutil-2.14.1.so
    /lib64/libutil.so.1
    ...
    Cela semble correspondre.

    ---

    Remarque : Tu peux exécuter la bibliothèque libc pour avoir des infos :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ~> /lib64/libc-2.14.1.so 
    GNU C Library stable release version 2.14.1 (20111007), by Roland McGrath et al.
    Copyright (C) 2011 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.
    There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
    PARTICULAR PURPOSE.
    Configured for x86_64.
    Compiled by GNU CC version 4.6.2.
    Compiled on a Linux 3.1.0 system on 2012-03-30.
    Available extensions:
            crypt add-on version 2.1 by Michael Glad and others
            GNU Libidn by Simon Josefsson
            Native POSIX Threads Library by Ulrich Drepper et al
            BIND-8.2.3-T5B
    libc ABIs: UNIQUE IFUNC
    For bug reporting instructions, please see:
    <http://www.gnu.org/software/libc/bugs.html>.
    libpthread donne aussi des infos.

    ---

    Les libs "supplémentaires" peuvent ou non être présentes (dépend des options de configuration de la création du package, de la configuration des options lors de la création de la lib ....).


    ---

    certaines options de compilations impliquent un link sans mention explicite de -l comme par exemple l'option -pthreads qui en plus de demander un lien vers libpthread positionne aussi certaines macros (gcc). Il y plus imbriqué : -fopenmp ajoute un -pthread implicite et d'autres bibliothèques :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    ~> gcc -o test test.c -pthread
    ~> ldd ./test
            linux-vdso.so.1 =>  (0x00003cb71000)
            libpthread.so.0 => /lib64/libpthread.so.0 (0x0000c09b1000)
            libc.so.6 => /lib64/libc.so.6 (0x0000c0621000)
            /lib64/ld-linux-x86-64.so.2 (0x0000c0bce000)
    ~> gcc -o test test.c -fopenmp
    ~> ldd ./test
            linux-vdso.so.1 =>  (0x0000741ff000)
            libgomp.so.1 => /usr/lib64/libgomp.so.1 (0x000082087000)
            libpthread.so.0 => /lib64/libpthread.so.0 (0x000081e6a000)
            libc.so.6 => /lib64/libc.so.6 (0x000081ada000)
            librt.so.1 => /lib64/librt.so.1 (0x0000818d2000)
            /lib64/ld-linux-x86-64.so.2 (0x000082295000)

  8. #8
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Citation Envoyé par jlliagre Voir le message
    Parce que dans le premier cas, le code généré n'appelle par floor. La phase d'optimisation du compilateur détecte que le paramètre passé à floor est une constante et donc que le calcul du résultat durant l'exécution est inutile.
    Salut,

    cette réflection m'a interpelé ... il est fort quand même gcc, il voit floor dans <math.h> (dans la glibc/gcc il y a un attribut const qui signifie même paramêtre -> même résultat). Il optimise en exécutant un floor(1.1) (donc en faisant appel à la libm) et place le résultat à la place de l'appel de fonction. Ça me paraît cohérent.

    Mais que se passe-t-il si on remplace (maladroitement) le #include <math.h> par le prototype naïf de floor :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // test.c
    #include <stdio.h>
    //#include <math.h>
     
    extern double floor(double);
     
    int main () {
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       return 0 ;
    }
    Pas d'attribut const cette fois ci ... donc l'appel à floor pourrait faire autre chose que renvoyer une valeur constante pour un paramètre constant (comme modifier une variable globale, renvoyer une valeur non constante, ...).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ~> gcc -o test test.c 
    ~> ldd test
            linux-vdso.so.1 =>  (0x00007fff995ff000)
            libc.so.6 => /lib64/libc.so.6 (0x00007f39f9891000)
            /lib64/ld-linux-x86-64.so.2 (0x00007f39f9c21000)
    ~> ./test 
    floor 1.1 : 1.000000
    Ah ben non .... toujours la même optimisation ?

    Mais alors que se passerait-il si je lui donne ma version de floor ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    //monfloor.c
     
    double floor(double x)
    {
      return 3.14;
    }
    avec le même test.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // test.c
    #include <stdio.h>
    //#include <math.h>
     
    extern double floor(double);
     
    int main () {
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       return 0 ;
    }
    On compile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ~> gcc -c test.c
    ~> gcc -c monfloor.c 
    ~> gcc -o test monfloor.o test.o 
    ~> ./test 
    floor 1.1 : 1.000000
    N'y aurait-il pas comme un bug de bonne volonté : je n'ai pas demandé de link avec la libm, j'ai fourni ma version de floor et pourtant on bypass mes choix et non seulement on écarte mon floor et on me le remplace sans que je demande quoi que ce soit par la version de la libm ????

    Ok ... forçons un appel qui ne peut-être optimisé :
    monfloor est inchangé, mais test.c devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // test.c
    #include <stdio.h>
    //#include <math.h>
     
    extern double floor(double);
     
    int main () {
       double d;
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       printf ("double value : ");
       scanf ("%lf", &d);
       printf ("floor(%lf)=%lf\n", d, floor(d));
       return 0 ;
    }
    Je vire tous les .o et test pour partir sur une compil propre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ~> rm *.o test
    ~> gcc -c monfloor.c 
    ~> gcc -c test.c 
    ~> gcc -o test test.o monfloor.o
    Jusque là tout va bien ... testons test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ~> ./test 
    floor 1.1 : 1.000000
    double value : 10.1
    floor(10.100000)=3.140000
    Ah ???? le premier floor est celui optimisé avec un appel à la libm, le second est le mien ????

    Le résultat est identique avec les options -O0 (pas d'optimisation) et -g (debug)

    Voyons quelle est l'adresse du bugzilla de gcc ?



    Remarque : le compilateur intel réagi correctement lui :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ~> /opt/intel/bin/icc -c test.c
    ~> /opt/intel/bin/icc -c monfloor.c 
    ~> /opt/intel/bin/icc -o test test.o monfloor.o
    ~> ./test 
    floor 1.1 : 3.140000
    double value : 100
    floor(100.000000)=3.140000
    Il va même cherche la libm tout seul :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ~> /opt/intel/bin/icc -o test test.o 
    ~> ./test 
    floor 1.1 : 1.000000
    double value : 10.22
    floor(10.220000)=10.000000

  9. #9
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par kwariz Voir le message
    Salut,

    cette réflection m'a interpelé ... il est fort quand même gcc, il voit floor dans <math.h> (dans la glibc/gcc il y a un attribut const qui signifie même paramêtre -> même résultat). Il optimise en exécutant un floor(1.1) (donc en faisant appel à la libm) et place le résultat à la place de l'appel de fonction. Ça me paraît cohérent.

    Mais que se passe-t-il si on remplace (maladroitement) le #include <math.h> par le prototype naïf de floor :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // test.c
    #include <stdio.h>
    //#include <math.h>
     
    extern double floor(double);
     
    int main () {
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       return 0 ;
    }
    Pas d'attribut const cette fois ci ... donc l'appel à floor pourrait faire autre chose que renvoyer une valeur constante pour un paramètre constant (comme modifier une variable globale, renvoyer une valeur non constante, ...).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ~> gcc -o test test.c 
    ~> ldd test
            linux-vdso.so.1 =>  (0x00007fff995ff000)
            libc.so.6 => /lib64/libc.so.6 (0x00007f39f9891000)
            /lib64/ld-linux-x86-64.so.2 (0x00007f39f9c21000)
    ~> ./test 
    floor 1.1 : 1.000000
    Ah ben non .... toujours la même optimisation ?

    Mais alors que se passerait-il si je lui donne ma version de floor ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    //monfloor.c
     
    double floor(double x)
    {
      return 3.14;
    }
    avec le même test.c
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // test.c
    #include <stdio.h>
    //#include <math.h>
     
    extern double floor(double);
     
    int main () {
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       return 0 ;
    }
    On compile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ~> gcc -c test.c
    ~> gcc -c monfloor.c 
    ~> gcc -o test monfloor.o test.o 
    ~> ./test 
    floor 1.1 : 1.000000
    N'y aurait-il pas comme un bug de bonne volonté : je n'ai pas demandé de link avec la libm, j'ai fourni ma version de floor et pourtant on bypass mes choix et non seulement on écarte mon floor et on me le remplace sans que je demande quoi que ce soit par la version de la libm ????

    Ok ... forçons un appel qui ne peut-être optimisé :
    monfloor est inchangé, mais test.c devient :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // test.c
    #include <stdio.h>
    //#include <math.h>
     
    extern double floor(double);
     
    int main () {
       double d;
       printf ("floor 1.1 : %f\n", floor(1.1)) ;
       printf ("double value : ");
       scanf ("%lf", &d);
       printf ("floor(%lf)=%lf\n", d, floor(d));
       return 0 ;
    }
    Je vire tous les .o et test pour partir sur une compil propre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ~> rm *.o test
    ~> gcc -c monfloor.c 
    ~> gcc -c test.c 
    ~> gcc -o test test.o monfloor.o
    Jusque là tout va bien ... testons test :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ~> ./test 
    floor 1.1 : 1.000000
    double value : 10.1
    floor(10.100000)=3.140000
    Ah ???? le premier floor est celui optimisé avec un appel à la libm, le second est le mien ????

    Le résultat est identique avec les options -O0 (pas d'optimisation) et -g (debug)
    Pas mal du tout. Mon compilo (gcc v4.4.5-8 de Debian Squeeze) a réagi pareil

    Citation Envoyé par kwariz Voir le message
    Remarque : le compilateur intel réagi correctement lui :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    ~> /opt/intel/bin/icc -c test.c
    ~> /opt/intel/bin/icc -c monfloor.c 
    ~> /opt/intel/bin/icc -o test test.o monfloor.o
    ~> ./test 
    floor 1.1 : 3.140000
    double value : 100
    floor(100.000000)=3.140000
    Il va même cherche la libm tout seul :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    ~> /opt/intel/bin/icc -o test test.o 
    ~> ./test 
    floor 1.1 : 1.000000
    double value : 10.22
    floor(10.220000)=10.000000
    Et g++ marche aussi...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  10. #10
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Pas mal du tout. Mon compilo (gcc v4.4.5-8 de Debian Squeeze) a réagi pareil



    Et g++ marche aussi...
    Ma version de gcc : 4.6.2 ; même comportement g++ donne un code correct (test.o + monfloor.o -> test) ou échoue (test.o -> test).

    Bon il est un peu tard pour faire du bugzilla mais je regarderai demain si le bug est connu.

    EDIT:
    En fait c'est encore pire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <stdio.h>
     
    double floor(double x)
    {
      return 3.14;
    }
     
    int main()
    {
      double x;
      x=1.1;
      printf("floor(%lf)=%lf\n", 1.1, floor(1.1));
      printf("floor(%lf)=%lf\n", x, floor(x));
     
      return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    > gcc -o test test.c
    > ./test
    floor(1.100000)=1.000000
    floor(1.100000)=3.140000

  11. #11
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut
    Citation Envoyé par kwariz Voir le message
    Ma version de gcc : 4.6.2 ; même comportement g++ donne un code correct (test.o + monfloor.o -> test) ou échoue (test.o -> test).

    Bon il est un peu tard pour faire du bugzilla mais je regarderai demain si le bug est connu.

    EDIT:
    En fait c'est encore pire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    #include <stdio.h>
     
    double floor(double x)
    {
      return 3.14;
    }
     
    int main()
    {
      double x;
      x=1.1;
      printf("floor(%lf)=%lf\n", 1.1, floor(1.1));
      printf("floor(%lf)=%lf\n", x, floor(x));
     
      return 0;
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    > gcc -o test test.c
    > ./test
    floor(1.100000)=1.000000
    floor(1.100000)=3.140000


    Belle pioche, kwariz
    Citation Envoyé par Donald "gcc" Knuth
    Undue optimisation is the root of all evil.
    Et en effet ça appelle Bugzilla. Retrace-leur tes différents essais car il y a différentes formes d'anomalies apparemment (les cas où ils optimisent indûment ou pas) (d'ailleurs ça peut leur servir même si le bug est déjà ouvert).

    PS: Ne crachons pas sur gcc, d'ailleurs, ils font un super et énorme boulot, on s'en sert tous les jours (PPS: je ne veux pas dire que quiconque ait dit du mal, hein!) On peut en dire autant d'ailleurs de tout le mouvement logiciel libre; je suis un grand admirateur de Richard Stallman pour ça, son oeuvre est aussi magnifique que courageuse.

  12. #12
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Le compilateur comporte un certain nombre de fonctions intrinsèques. Autrement dit, la compilateur sait lui-même calculer le résultat de ces fonctions lorsqu'il connait la valeur des arguments. C'est le cas ici de floor() pour ce compilateur. La liste de ces fonctions dépend du compilateur utilisé.
    Ceci permet au compilateur de remplacer l'appel à la fonction correspondante de la bibliothèque par une simple valeur et d'accélérer l'exécution du programme.

    Le bug, dans l'exemple, est de redéfinir la fonction standard floor() sans précautions.
    Le défaut du compilateur est de ne pas interdire la redéfinition d'une fonction intrinsèque ou au minimum d'émettre un warning dans ce cas.
    Il doit sinon laisser à la responsabilité du programmeur de pouvoir les utiliser ou non (après tout, celui-ci doit savoir ce qu'il fait) . C'est le cas de gcc qui a les options -fno-builtin et -fno-builtin-function. Voir 5.46 Other built-in functions provided by GCC

    Remarque : le compilateur intel réagi correctement lui :
    Mais floor() est-elle bien une fonction intrinsèque de ce compilateur et le compilateur a t-il, constatant la présence d'une fonction "utilisateur" floor(), décidé d'utiliser cette dernière ?
    Si floor() n'est pas une fonction intrinsèque, ce comportement est normal

  13. #13
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Salut,

    oui c'est en substance la réponse que m'a donné un développeur gcc. Ce comportement est normal et si je n'en veux pas je dois utiliser l'option -fno-builtin (ou dérivé, ou utiliser une version de gcc où ce comportement est désactivé par défaut). g++ a une autre comportement car les fonctions math sont dans le namespace Math. Le compilateur va émettre un warning si la signature de la fonction est différente de celle du builtin.

    conclusion: ce n'est pas un bug

  14. #14
    Modérateur
    Avatar de jlliagre
    Homme Profil pro
    Ingénieur support avancé & développement
    Inscrit en
    Juin 2007
    Messages
    2 695
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur support avancé & développement
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 2 695
    Par défaut
    Citation Envoyé par denispir Voir le message
    D
    PS: C'est typiquement le genre de truc qui me rend un peu colère, ça: comment un utilisateur est-il sensé savoir ça? D'accord, on peut toujours dire RTFM et tout ça mais; je suis sûr que c'est marqué noir sur blanc... mais où?
    Il ne faut pas chercher bien loin:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    $ man floor
    ...
    FLOOR(3)                   Linux Programmer's Manual                  FLOOR(3)
    
    NAME
           floor,  floorf,  floorl - largest integral value not greater than argu‐
           ment
    
    SYNOPSIS
           #include <math.h>
    
           double floor(double x);
           float floorf(float x);
           long double floorl(long double x);
    
           Link with -lm.
          
          ...

  15. #15
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut
    Citation Envoyé par diogene Voir le message
    Le bug, dans l'exemple, est de redéfinir la fonction standard floor() sans précautions.
    Le défaut du compilateur est de ne pas interdire la redéfinition d'une fonction intrinsèque ou au minimum d'émettre un warning dans ce cas.
    C'est ça le problème: les concepteurs gcc ne peuvent pas à la fois:
    * Autoriser la redéfinition de fonctions prédéfinies, sans même un message d'erreur,
    * et optimiser sans prévenir en précalculant leurs résultats à la compilation.
    Ca me semble incompatible. De toute façon, vue l'absence d'espace de noms en C (le défaut qui me gêne le plus, d'ailleurs), au moins un warning en cas de redéfinition de quoi que ce soit de prédéfini est le minimum (et en standard, sans option de compilation spéciale pour ça).

    denis

  16. #16
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    En fait, le comportement "à la gcc" est consistant.
    La norme définit les fonctions standards qui sont publiques à travers les headers standards. Ces fonctions sont réservées et ne doivent pas être redéfinies (*).
    Il est donc normal, du moins logique et cohérent, que sans indications supplémentaires (via un -fno-builtin par exemple) le compilateur assume que floor soit la fonction standard et optimise comme il le peut. Le standard c99 (par exemple) stipule que si une de ces fonctions est redéfinie le comportement du compilo est non définit (ce qui finalement sied aussi à icc ...).
    Ce qui à la limite me semble étrange, est que l'optimisation soit faite "tout le temps" et que le seul moyen de l’empêcher soit de désactiver le builtin, quoique, le seul but de son existence est ce genre d'optimisation.

    (*): merci au forum de refraîchir ma mémoire sur les basiques

  17. #17
    Membre confirmé
    Profil pro
    amateur
    Inscrit en
    Avril 2012
    Messages
    145
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : amateur
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2012
    Messages : 145
    Par défaut
    Citation Envoyé par kwariz Voir le message
    En fait, le comportement "à la gcc" est consistant.
    La norme définit les fonctions standards qui sont publiques à travers les headers standards. Ces fonctions sont réservées et ne doivent pas être redéfinies (*).
    Il est donc normal, du moins logique et cohérent, que sans indications supplémentaires (via un -fno-builtin par exemple) le compilateur assume que floor soit la fonction standard et optimise comme il le peut. Le standard c99 (par exemple) stipule que si une de ces fonctions est redéfinie le comportement du compilo est non définit (ce qui finalement sied aussi à icc ...).
    Ce qui à la limite me semble étrange, est que l'optimisation soit faite "tout le temps" et que le seul moyen de l’empêcher soit de désactiver le builtin, quoique, le seul but de son existence est ce genre d'optimisation.
    Ah, d'accord, je savais pas que le std spécifiait qie le std ne doit pas être violé. Quoique ce soit peut-être "le seul but de son existence", au comité de std (je déconne)

    Denis

  18. #18
    Invité de passage
    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2012
    Messages
    1
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Novembre 2012
    Messages : 1
    Par défaut
    slt
    J'utilise Visual Studio 2010 j'aimerai savoir comment utiliser la bibliothèque math.h dans cet environnement. En effet mon code ne parvient pas a calculer cos et sin
    Merci d'avance

  19. #19
    Expert éminent

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 202
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 202
    Par défaut
    Citation Envoyé par asndic Voir le message
    slt
    J'utilise Visual Studio 2010 j'aimerai savoir comment utiliser la bibliothèque math.h dans cet environnement. En effet mon code ne parvient pas a calculer cos et sin
    Merci d'avance
    math.h est implémenté a part, il faut lier avec la lib math.

    c'est probablement m.dll, mais google ou un autre d'entre nous te diras le bon nom (pour linux, c'est libm.so => option de compilation -lm)

    Dans visual studio, il y a probablement une option explicite pour lier avec.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème : problème include avec 2 Form (pitié !)
    Par antoile dans le forum VC++ .NET
    Réponses: 6
    Dernier message: 04/05/2007, 16h02
  2. Problème include
    Par djul94 dans le forum Langage
    Réponses: 10
    Dernier message: 26/03/2007, 13h49
  3. Problème includes pas conformes et incomplets
    Par souviron34 dans le forum Dev-C++
    Réponses: 6
    Dernier message: 30/01/2007, 20h57
  4. [VC++] Problème include de header
    Par Yellowmat dans le forum MFC
    Réponses: 10
    Dernier message: 08/12/2005, 13h50
  5. problème include avec win 2003 / IIS6
    Par fredoche dans le forum ASP
    Réponses: 3
    Dernier message: 26/09/2005, 17h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo