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 :

constructeur non reconnu


Sujet :

C++

  1. #21
    Membre confirmé

    Homme Profil pro
    développeur à la maison
    Inscrit en
    Septembre 2006
    Messages
    361
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : développeur à la maison

    Informations forums :
    Inscription : Septembre 2006
    Messages : 361
    Points : 452
    Points
    452
    Billets dans le blog
    15
    Par défaut
    constexpr int
    il suffisait de m'en parler plus tôt, j'aurai pas insisté. Je n'ai pas la science infuse

  2. #22
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par matser Voir le message
    il trouvera la valeur immédiate 3 dans le programme
    Et le programme, à ton avis, il est composé de quoi au final, si ce n'est de données et d'instructions processeur

    Dés que le processeur doit utiliser une valeur quelconque issue du programme, il doit bien la trouver quelque par bon sang de bon soir. Il ne peut pas la trouver dans l'air du temps ou dans la phase de la lune!!!

    c'est pourtant pas compliqué: le pré-processeur remplacera toutes les occurrences de "abc" par "3". le compilateur ne saura même pas que "abc" à été utilisé, il n'y verra que "3" à la place.
    Ca je suis bien d'accord. Mais le compilateur va traduire toutes tes valeurs et tes instructions en code binaire qui sera compréhensible par le processeur. Et si le compilateur voit la valeur 3 quelque part, hé bien, il va inscrire cette valeur soit dans un registre, soit dans la pile, soit à une adresse mémoire quelconque pour que le processeur puisse la retrouver d'une manière ou d'une autre.

    Parce que si on ne retrouve pas la valeur binaire correspondant à 3 "à un endroit quelconque" où le processeur peut y avoir accès, on pourra danser sur la tête, on pourra pisser contre le vent ou dansser la carmagnole me processeur ne pourra pas l'utiliser.

    Ta vision des choses s'arrête visiblement au compilateur, mais il faut bien comprendre qu'il y a quelque chose après le compilateur. Et ce quelque chose est trois fois rien : ce n'est jamais que le système sur lequel le programme est exécuté une fois que le code a été compilé

  3. #23
    Membre confirmé

    Homme Profil pro
    développeur à la maison
    Inscrit en
    Septembre 2006
    Messages
    361
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : développeur à la maison

    Informations forums :
    Inscription : Septembre 2006
    Messages : 361
    Points : 452
    Points
    452
    Billets dans le blog
    15
    Par défaut
    Parce que si on ne retrouve pas la valeur binaire correspondant à 3 "à un endroit quelconque"
    valeur immédiate
    toutes les chaine "abc" seront remplacés par "3" avant la compilation, pas pendant.
    à l'IUT on m'a aussi appris ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define  TAB {1,2,3}
    int tab[3]=TAB;
    après le préprocesseur,le compilo ne verra que:
    toute les chaines "TAB" seront remplacé par la chaine "{1,2,3}", avant la compilation
    deviendra
    sinon, j'ai essayé constexpr et effectivement, ça marche

  4. #24
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par matser Voir le message
    valeur immédiate
    toutes les chaine "abc" seront remplacés par "3" avant la compilation, pas pendant.
    à l'IUT on m'a aussi appris ça:
    Mais ce que tu ne veux pas comprendre, c'est que mov ax,3 n'est encore qu'une abstraction de ce qui sera fait par le compilateur, car, en instruction processeur, nous aurons quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    00001100000001100100000011
    (les valeurs, à part le 3 ne sont surement pas justes. Je suis même pas sur qu'elles comportent le bon nombre de bits) où 0000110000 correspondra à l'instruction mov dans le jeu d'instructions du processeur, où 00011001 correspondra à permettra au processeur de savoir qu'il doit copier une valeur dans le registre ax et où 00000011 correspondra à la valeur qu'il doit copier dans le registre en question.

    Donc, 3 prend de la place dans le programme, mais il se trouve aussi forcément à un endroit où il sera accessible par le processeur.

    De même, si l'instruction demande de copier la valeur qui se trouve dans ax à une adresse mémoire, on retrouvera forcément la valeur 0000011 "quelque part" en mémoire.

    Autrement dit, n'importe quelle valeur, qu'il s'agisse d'une constante de compilation ou non se retrouvera forcément, à un moment ou à un autre, quelque par en mémoire ou dans un registre (et parfois même à plusieurs endroits).

    Il n'y a que deux exceptions (du moins à ma connaissance, s'il y en a plus, nous les compterons sur les doigts d'une main) à cet état de fait:

    1- L'utilisation de l'opérateur ternaire ? avec deux valeur connues à la compilation; ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     contante1 <= constante2 ? truc : machin;
    qui, si constante2 vaut 3 sera transformé en truc si constante1 vaut 0,1,2ou 3 et en machin si constante1 vaut plus de trois

    2- une boucle proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(Type i=0; i<constante1;++1){
        truc
    }
    qui, le déroulement des boucles se faisant, pourrait prendre la forme de
    (enfin, pour autant que l'on soit dans une situation dans laquelle on peut effectivement dérouler la boucle)

    Et encore! 9 fois sur 10, si constante1 ou constante2 est obtenu par paramètre ou par retour de fonction, cela ne fonctionnera pas

    Mais note bien que tout ce qui importe, c'est que constante1 et constante2 soient connues à la compilation.

    C'est à dire que cela fonctionnera -- effectivement -- avec un #define, mais aussi
    • avec la valeur de retour de sizeof()
    • avec une valeur énumérée
    • avec n'importe quelle constante accessible par le compilateur (par exemple cont int truc=3
    • lorsque l'on utilise une valeur numérique comme paramètre template (ex: template <int NUM> struct machin{/* ... */};)
    • j'oublie peut-être un ou deux cas


    Note enfin qu'un code proche de const int truc=3; pourrait (il me semble du moins) tout aussi bien se traduire au final par la valeur 3 (plutôt que par la récupération de la valeur d'une variable) grâce à la suppression des variables inutiles; si toutes les expressions qui utilisent truc sont évaluables à la compilation

  5. #25
    Membre confirmé

    Homme Profil pro
    développeur à la maison
    Inscrit en
    Septembre 2006
    Messages
    361
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Tarn et Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : développeur à la maison

    Informations forums :
    Inscription : Septembre 2006
    Messages : 361
    Points : 452
    Points
    452
    Billets dans le blog
    15
    Par défaut
    "abc" n'est pas une variable, c'est un morceau de chaine de caractère contenu dans le code source
    le compilateur ne trouvera pas de "abc" dans le code source. il verra 3 à la place.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    abc>4?std::cout<<"plus"<<std::endl; : std::cout<<"moins"<<endl;
    le compilateur ne verra que ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    3>4?std::cout<<"plus"<<std::endl; : std::cout<<"moins"<<std::endl;
    mais bon, je veux bien utiliser constexpr si c'est plus moderne

  6. #26
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Oui, je sais très bien que le compilateur verra 3 et non abc, mais ce n'est pas le problème!

    Le problème, c'est que le compilateur va utiliser le code (qui a déjà été altéré par le passage du préprocesseur) pour générer un ensemble d'instructions sous une forme binaire (on est donc déjà "un cran plus loin" que l'assembleur) qui sera compréhensible par le processeur.

    Or, ces instructions et les données qui permettent aux instructions processeur de travailler sont forcément mises à disposition du processeur en mémoire, sous une forme ou sous une autre.

    Compiles un programme minimal qui utilise une constante de compilation (crée dans ton code de la manière que tu veux), et ouvre le avec un éditeur hexadécimal et tu te rendra compte que la valeur de ta constante se trouve dans le corps du programme.

    Comme le corps du programme doit être chargé en mémoire pour que ton ordinateur puisse l'exécuter, ne vient pas me dire qu'un #define ne coute rien (je viens de citer les deux seules exceptions que je connaisse)!

    Et je viens surtout pas me dire qu'il n'y a que le define qui ne coute rien dans certaines circonstances, car ce n'est pas vrai! C'est vrai pour tout ce qui peut être considéré par le compilateur comme une constante de compilation; ce qui va des valeurs énumérées à la définition de données typées et nommées, en passant par les #define et la valeur de retour de certaines fonctions (sizeof entre autres).
    Et, comme il en va de même de toutes les constantes de compilation, ne vient pas me dire que le seul moyen d'obtenir une constante passe par le #define. C'est effectivement l'un des moyens que l'on a à notre disposition pour définir une constante, mais on en a de bien meilleurs dont il s'agit d'user et d'abuser pour éviter les problèmes!

  7. #27
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Points : 16 213
    Points
    16 213
    Par défaut
    Dans le cas d'un #define abc 3, le compilateur ne verra que 3, pas abc, qui sera effectivement résolu par le préprocesseur. Jusque là, personne ne dit le contraire.

    Dans le cas d'un int const abc=3;, le compilateur verra des usages d'abc. Usages qu'il pourra valider par rapport au système de type en particulier. Je pense que là aussi, tout le monde est d'accord.

    Là où le désaccord commence, c'est quand tu semble dire que la seconde situation implique que le programme résultant est peut-être moins performant. C'est tout simplement faux. Tout comme il y a plusieurs phases avant d'arriver au compilateur à proprement parler, il y a plusieurs phases après. L'une des phases d'optimisation a pour but de propager les valeurs constante, afin d'éviter les calculs inutiles. Lors de cette phase (où abc en tant que chaîne a déjà disparu, le compilateur sait juste qu'il s'agit de la 42ème variable déclarée dans le programme), la variable sera remplacée par 3, et cette valeur sera propagée par la suite.

    Je te propose l'expérience suivante :
    Va à l'adresse https://godbolt.org/g/GZSwWu j'ai entré le code suivant, et il te montre le code compilé correspondant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #include <iostream>
     
    #define d1 3
    int const d2 = 3;
     
    int main()
    {
        int a = d1 * 5;
        int b = d2 * 4;
        std::cout << a << b;
    }
    Tu peux voir dans la fenêtre de droite, avec un arbre, que dans un cas, on multiplie 3 par 5, alors que dans l'autre cas, ou multiplie d2 par 5. Mais cet arbre n'est qu'un intermédiaire de la compilation, et dans le code assembleur final, tu ne vois plus aucune mention de la valeur 3. Ni venant de d1, ni de d2. Les valeurs qui apparaissent sont 15 et 12, c'est à dire le résultat des multiplications. Donc dans les 2 cas, les constantes ont été résolues pendant la compilation, et le compilateur ne s'est pas arrêté là, mais a continué à résoudre tout ce qu'il pouvait avant de générer le code final qui ne contient aucune multiplication.

    Conclusion : Entre #define et constante, les constantes offrent plus de sécurité, et les deux ont les même performances. Il faut donc privilégier les constantes.
    PS : Les constexpr sont avant tout un moyen de forcer encore plus de calculs pendant la compilation, et non pendant l'exécution.
    PPS : Une extension intéressante du programme ci dessus est :
    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 <iostream>
     
    #define d1 3
    int const d2 = 3;
    int d3 = 3;
     
    int main()
    {
        int d4 = 3;
        int a = d1 * 5;
        int b = d2 * 4;
        int c = d3 * 7;
        int d = d4 * 8;
        std::cout << a << b << c << d;
    }
    Si tu l'entres sur le site, tu pourra voir que même non constant, l'appel d4*8 est résolu à la compilation en 24. Par contre l'appel à d3*7 ne l'est pas, parce que le compilateur n'arrive pas à voir que la variable globale d3 n'est jamais modifiée dans le programme (alors que pour une variable locale, c'est plus simple à démontrer).

+ Répondre à la discussion
Cette discussion est résolue.
Page 2 sur 2 PremièrePremière 12

Discussions similaires

  1. Constructeur non reconnu
    Par suxxa dans le forum Langage
    Réponses: 4
    Dernier message: 07/02/2013, 14h15
  2. Réponses: 4
    Dernier message: 23/09/2007, 19h10
  3. [EJB] [JSP] Méthode EJB non reconnue dans jsp
    Par stago dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 06/07/2004, 09h52
  4. Creation de table, caractère non reconnu
    Par Missvan dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 17/02/2004, 13h28
  5. xslt_create() non reconnu
    Par BRAUKRIS dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 11/12/2003, 14h43

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