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

Langage Delphi Discussion :

Ordre d’évaluation des paramètres d'une fonction [Infos]


Sujet :

Langage Delphi

  1. #1
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut Ordre d’évaluation des paramètres d'une fonction
    Salut a tous.

    Ce n'est pas une question que je vais poser aujourd'hui, mais plutot une information importante dont je n'avais pas imaginé l'impacte avant de tomber dessus.

    Commençons par une petite devinette :
    A votre avis, que va afficher le code suivant ?
    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
     
    type
      MonType = Integer;
    var
      cpt: MonType = 1;
     
    function NextCompteur: MonType;
    begin
      Result := cpt;
      cpt := cpt+1;
    end;
     
    procedure Affiche(i1, i2, i3, i4, i5, i6: MonType);
    begin
      ShowMessage(        IntToStr(i1) +
                  ' - ' + IntToStr(i2) +
                  ' - ' + IntToStr(i3) +
                  ' - ' + IntToStr(i4) +
                  ' - ' + IntToStr(i5) +
                  ' - ' + IntToStr(i6) );
    end;
     
    begin //Main
      cpt := 1;
      Affiche(NextCompteur(), NextCompteur(), NextCompteur(), NextCompteur(), NextCompteur(), NextCompteur());
    end.
    Vous avez répondu "1 - 2 - 3 - 4 - 5 - 6" ? .... perdu
    Vous avez répondu "6 - 5 - 4 - 3 - 2 - 1" ? .... perdu

    La bonne réponse était "6 - 5 - 4 - 1 - 2 - 3" !
    La raison : la convention d'appel par defaut est "register", qui utilise jusqu'a 3 registres de la CPU. Donc i1, i2 et i3 seront placés dans les registres, et i4, i5, i6 sur la pile.
    Mais ce qui est etonnant, c'est qu'il va evaluer les parametres de la pile en premier, et de gauche à droite, puis ceux des registres, mais de droite à gauche !

    Autre chose etonnante, c'est que si la procedure Affiche est une methode d'objet, le resultat est "6 - 5 - 1 - 2 - 3 - 4" ! Je penses que cela est du au fait que le premier parametre est le pointeur de l'objet sur lequel est appelé la fonction ( = le self), et donc il ne reste plus que 2 registres disponibles.

    Par contre, si on utilise, alors l'ordre est bien de gauche à droite. En effet, les int64 ne logent pas dans un registre, donc tout est passé sur la pile.

    Etonnant non ? (et source de pieges )

  2. #2
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Très bonne remarque !

    j'ai répondu "1 - 2 - 3 - 4 - 5 - 6" ? .... puisque "De gauche à droite"

    Perso, je me suis longtemps contenté du 1 premier paramètre pour des routines assembleur en utilisant EAX comme 1er paramètre et valeur de retour

    c'est fraichement en C++, qu'avec __fastcall, que j'ai exploité EAX et EDX, peut-être qu'un jour j'oserais ECX

    Pour la méthode d'objet, oui, le self dans EAX, c'est bien connu, j'ai découvert cela avec TMethod et MethodAdress quand j'ai voulu jouer un peu trop avec les RTTI

    Faudrait vérifier en XE2 pour le compilateur 64 bits qui a forcément des registres pour contenir les int64 directement

    Tu as du avoir un cas bien vicieux, c'est rare d'avoir besoin de connaître l'ordre des paramètres !
    En général, si j'ai un ordre d'execution, je vais mettre des variables temporaires tout en gérant le succes à chaque étape, la fonction finale n'étant executée que si tout c'est bien passé, et c'est très très rare, surement parce que j'utilise bcp d'objet ou record et donc peu de paramètre !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  3. #3
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    En fait je suis tombé sur le cas en faisant de la serialisation. J'ai une fonction qui ressemble à ca:
    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
     
    function ReadMonRecord(ASerializer: TSerializer): TMonRecord;
    begin
      Result.prop1 := ASerializer.ReadFloat;
      Result.prop2 := ASerializer.ReadFloat;
      Result.prop3 := ASerializer.ReadFloat;
    end;
     
    procedure TMonObjet.Load(ASerializer: TSerializer);
    begin
      FMonChamp := TMonChamp.Create(ReadMonRecord(ASerializer){r1}, ReadMonRecord(ASerializer){r2});
      //Précédemment sauvé par:
      // WriteMonRecord(FMonChamp.r1);
      // WriteMonRecord(FMonChamp.r2);
    end;
    et j'ai ete etonné que le r1 et r2 de monChamp soient inversés ! Surtout que ce sont des record, donc pas compatibles avec un registre. Sauf que ce sont des pointeurs qui sont reellement passés, donc ils sont bien mis dans les registres.

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Citation Envoyé par guillemouze Voir le message
    ! Surtout que ce sont des record, donc pas compatibles avec un registre. Sauf que ce sont des pointeurs qui sont reellement passés, donc ils sont bien mis dans les registres.
    C'est effectivement curieux, faudrait voir le comportement si tu modifies les record dans ton create !
    Parce que normalement, c'est un passage par valeur, donc si tu modifies à l'intérieur cela n'altère pas la valeur après la fonction, un système de Copy-On-Write ? Non, il y a que pour la String !!!
    ou une compilation avec optimisation assez brutale ! Et c'est limite flippant !

    ou alors tu nous cache, un const en mot clé dans le TMonChamp.Create ?
    Et cela me semblerait bien plus cohérent !

    @sjrd, si tu passes par là ...
    C'est quoi un "record longs" dans "Les chaînes courtes, variants, tableaux et record longs, bien que plus grands que 4 octets, sont transmis par adresse, et entrent donc bien dans les registres" extrait du tutoriel

    record longs => sizeof(record) > 4 octets ?
    C'est pas si long que ça alors ! ça ne fait que 32 bits

    Car perso, j'ai une grosse différence entre

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct TMonRecord
    {
      int prop1; // step + 1
    };
    Mise en Registre ! OK !
    6, 5, 4, 1, 2, 3
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    struct TMonRecord
    {
      double prop1; // step + 1
      double prop2; // step + 0.1
      double prop3; // step + 0.01
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void __fastcall Affiche(TMonRecord i1, TMonRecord i2, TMonRecord i3, TMonRecord i4, TMonRecord i5, TMonRecord i6)
    Et je n'ai plus de mise en registre !!! Oups ! Une Théorie qui s'envole !
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    1 	1.1 	1.01
    2 	1.2 	1.02
    3 	1.3 	1.03
    4 	1.4 	1.04
    5 	1.5 	1.05
    6 	1.6 	1.06
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    void __fastcall Affiche(const TMonRecord &i1, const TMonRecord &i2, const TMonRecord &i3, const TMonRecord &i4, const TMonRecord &i5, const TMonRecord &i6)
    Mise en Registre ! OK ! le mot clé const en delphi donne le même résultat que le passage par const référence
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    6 	1.6 	1.06
    5 	1.5 	1.05
    4 	1.4 	1.04
    1 	1.1 	1.01
    2 	1.2 	1.02
    3 	1.3 	1.03
    je suis en C++Builder mais __fastcall c'est le register pour compatibilité VCL !

    On devrait avoir le même résultat !

    Refais ton test avec la bonne structure !
    Avec un type stockable sur 4 octets, cela peut fausser le test !


    Effectivement, c'est tout à fait le genre de code où je vais mettre des variables temporaires ! En fait non, en me connaissant, j'aurais plutôt une méthode TMonChamp.LoadFromStream ou LoadFromSerializer qui appelerait successivement les deux ReadMonRecord !

    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
    procedure TMonObjet.Load(ASerializer: TSerializer);
    begin
      FMonChamp := TMonChamp.Create();
      FMonChamp.Load(ASerializer);
    end;
     
    procedure TMonChamp.Load(ASerializer: TSerializer);
    begin
      ReadMonRecord(FMonChamp.r1, ASerializer);
      ReadMonRecord(FMonChamp.r2, ASerializer);
    end;
     
    procedure ReadMonRecord(var AMonRecord: TMonRecord; ASerializer: TSerializer);
    begin
      AMonRecord.prop1 := ASerializer.ReadFloat;
      AMonRecord.prop2 := ASerializer.ReadFloat;
      AMonRecord.prop3 := ASerializer.ReadFloat;
    end;
    Surtout que je suppose que tu as un autre constructeur de TMonChamp qui initialize des valeurs par défaut lorsque fais la toute 1ere saisie !?

    Moi, ça fait bien longtemps que je ne fais plus de fonction de sérialization, un objet qui héritent de TComponent, des propriétés publiées et nos amis ReadComponent\WriteComponent\ObjectTextToBinary\ObjectBinaryToText
    Tu ne poses plus aucune question, c'est pas léger mais bien efficace !

    Sinon, c'est de la DB et mes objets encapsule des DataSet !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    @sjrd, si tu passes par là ...
    C'est quoi un "record longs" dans "Les chaînes courtes, variants, tableaux et record longs, bien que plus grands que 4 octets, sont transmis par adresse, et entrent donc bien dans les registres" extrait du tutoriel

    record longs => sizeof(record) > 4 octets ?
    C'est pas si long que ça alors ! ça ne fait que 32 bits
    Un record long est bien tel que SizeOf(record) > 4 octets.

    Citation Envoyé par ShaiLeTroll Voir le message
    Et je n'ai plus de mise en registre !!! Oups ! Une Théorie qui s'envole !
    Plus de mise en registre, ou ordre d'évaluation perturbé ? Tu devrais mettre un point d'arrêt au moment de l'appel et faire Ctrl+Alt+C pour ouvrir le débogueur ASM. Tu verras ainsi précisément ce qui se passe.

    J'émets des doutes sérieux sur le fait que j'ai pu me planter à ce niveau, parce que ça serait apparu comme bug dans Sepi, et là j'utilise quand même Sepi tous les jours dans FunLabyrinthe, avec des milliers de lignes de code compilées par Sepi.

    Quant à la sérialisation, j'ai trois méthodes :
    Soit ce sont des types non-objets, dans ce cas j'utilise mon truc tout fait dans ScSerializer.pas. Plus besoin de recoder quoi que ce soit : il découvre tout par RTTI.

    Soit ce sont des objets, et alors je code des méthodes SaveToStream et constructeurs LoadFromStream ad-hoc (les unités compilées Sepi sont sérialisées comme ça).

    Enfin, dans FunLabyrinthe, j'ai recodé un système de sérialisation basé sur les RTTI et propriétés publiées, mais qui est genre 10 fois mieux que celui fait pour la VCL. Celui-ci enregistre en XML.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Citation Envoyé par sjrd Voir le message
    Plus de mise en registre, ou ordre d'évaluation perturbé ?
    Oui, c'est un vilain abus de langage, ma remarque ne portait que sur l'ordre d'évaluation des paramètres !
    Pour la mise en registre, je n'ai absolument pas vérifié, je n'ai jamais eu besoin de pousser les choses aussi loin !

    D'ailleurs pourquoi un tel phénomène ?

    Citation Envoyé par sjrd Voir le message
    J'émets des doutes sérieux sur le fait que j'ai pu me planter à ce niveau...
    Pourquoi dis-tu cela ?
    On a pas parlé de Bug ou d'Erreur, j'ai juste fait appel à tes lumières, tu es surement l'un des plus qualifiés pour nous répondre à ce sujet vu tes travaux sur les conventions d'appel des procédures "normales" et des méthodes !
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  7. #7
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Pourquoi dis-tu cela ?
    On a pas parlé de Bug ou d'Erreur, j'ai juste fait appel à tes lumières, tu es surement l'un des plus qualifiés pour nous répondre à ce sujet vu tes travaux sur les conventions d'appel des procédures "normales" et des méthodes !
    Parce que tu disais "Une théorie qui s'envole !". Je comprenais cette phrase comme parlant de mon tutoriel.

    Sinon c'est pas vraiment mes travaux sur les conventions d'appel... Ce tuto n'est qu'une conséquence des travaux que j'ai effectués pour pouvoir coder Sepi

    Pour l'anecdote, Sepi fait bien "pire" en matière de manipulations de la pile et des registres, pour gérer l'interface entre le code natif et le code interprété par Sepi. Si vous n'êtes pas trop sensible (), vous pouvez jeter un oeil à SepiInCalls.pas.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  8. #8
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Au fait je relis ceci :
    Citation Envoyé par ShaiLeTroll Voir le message
    C'est effectivement curieux, faudrait voir le comportement si tu modifies les record dans ton create !
    Parce que normalement, c'est un passage par valeur, donc si tu modifies à l'intérieur cela n'altère pas la valeur après la fonction, un système de Copy-On-Write ? Non, il y a que pour la String !!!
    ou une compilation avec optimisation assez brutale ! Et c'est limite flippant !

    ou alors tu nous cache, un const en mot clé dans le TMonChamp.Create ?
    Et cela me semblerait bien plus cohérent !
    En fait l'appelant donne toujours, "bêtement", l'adresse de son record en local. L'appelé reçoit donc bien l'adresse originale.

    Mais c'est le code de l'appelé qui, au début, recopie le record pointé par cette adresse dans une variable locale. C'est là, et seulement là, que se trouve la différence entre const et pas const : l'appelé travaille avec l'adresse originale, ou avec la variable locale dans laquelle il a copié le record.

    Ceci s'applique aussi aux tableaux, d'ailleurs.
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  9. #9
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Parce que normalement, c'est un passage par valeur, donc si tu modifies à l'intérieur cela n'altère pas la valeur après la fonction, un système de Copy-On-Write ? Non, il y a que pour la String !!!
    ou une compilation avec optimisation assez brutale ! Et c'est limite flippant !

    ou alors tu nous cache, un const en mot clé dans le TMonChamp.Create ?
    Et cela me semblerait bien plus cohérent !
    non non, pas de const (ca aurait pu et du etre le cas d'ailleurs !).
    Etrangement, ca ne m'etonne pas qu'il mette les records dans des registres. Ce sont des suppositions que je me suis faites sur les modificateurs des parametres, mais je penses que je ne suis pas loin de la verité :
    - var & out : un pointeur vers le record original est transmis
    - const : idem que pour var, sauf que c'est le compilateur qui verifie et raise si le contenu tente d'etre modifié
    - rien : l'appelant (ou l'appelé ?) fait une copie du record, transmet un pointeur dessus, puis libere la copie au retour de la fonction

    Citation Envoyé par ShaiLeTroll Voir le message
    Refais ton test avec la bonne structure !
    Avec un type stockable sur 4 octets, cela peut fausser le test !
    Effectivement, c'est etrange, moi j'ai testé avec un TMonRecord qui contenait un int + un shortstring + un double, j'avais toujours le meme resultat (mais je n'ai testé que le int de mon record)

    Citation Envoyé par ShaiLeTroll Voir le message
    En fait non, en me connaissant, j'aurais plutôt une méthode TMonChamp.LoadFromStream ou LoadFromSerializer qui appelerait successivement les deux ReadMonRecord !
    C'est ce que je fais en general, sauf que dans ce cas la je ne sauve pas l'objet complet (qui comporte bien plus de champs que 2 records), juste ce qui me sert a le recreer tel que j'en ai besoin.

    Citation Envoyé par ShaiLeTroll Voir le message
    Moi, ça fait bien longtemps que je ne fais plus de fonction de sérialization, un objet qui héritent de TComponent, des propriétés publiées et nos amis ReadComponent\WriteComponent\ObjectTextToBinary\ObjectBinaryToText
    C'est pas un peu plus lourd ? Je n'ai pas eu l'occasion de tester car j'ai ajouté la serialisation sur le projet qui etait deja bien avancé, avec des parties communes avec d'autres projets

  10. #10
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par sjrd Voir le message
    Mais c'est le code de l'appelé qui, au début, recopie le record pointé par cette adresse dans une variable locale. C'est là, et seulement là, que se trouve la différence entre const et pas const : l'appelé travaille avec l'adresse originale, ou avec la variable locale dans laquelle il a copié le record.
    Bon bah voila j'ai ma reponse, le temps que j'ecrive mon message, tu as eu le temps d'y repondre avant que je pose la question !

Discussions similaires

  1. Réponses: 1
    Dernier message: 27/11/2008, 10h55
  2. Réponses: 2
    Dernier message: 28/04/2008, 20h04
  3. Réponses: 3
    Dernier message: 16/05/2007, 10h03
  4. Réponses: 3
    Dernier message: 14/05/2007, 15h24
  5. Evaluations des paramètres d'une fonction
    Par WebPac dans le forum Langage
    Réponses: 15
    Dernier message: 06/10/2005, 09h46

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