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

Delphi Discussion :

Variable de For après la boucle


Sujet :

Delphi

  1. #1
    Membre expérimenté
    Homme Profil pro
    ‫‬
    Inscrit en
    Septembre 2024
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : ‫‬

    Informations forums :
    Inscription : Septembre 2024
    Messages : 144
    Par défaut Variable de For après la boucle
    Dans les premières versions de Delphi, l'utilisation de la variable For après la boucle est déconseillée et sa valeur peut être indéfinie. pourtant je suis tombé sur ce bout de code dans TOleControl.GetEventMethod qui montre l'inverse .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
       for Index := 0 to FControlData^.EventCount-1 do
      begin
        if DispID = PID^ then
          break;
        Inc(PID);
      end;
     
      if Index = FControlData^.EventCount then
      begin
        Method.Code := nil;
        Method.Data := nil;
        Exit;
      end;
    ..

  2. #2
    Membre émérite
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    404
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 404
    Par défaut
    le compteur est dans un état indéterminé à la fin de la boucle sauf après un break ou un exit, mais le code me parait quand même bancal

  3. #3
    Membre chevronné Avatar de der§en
    Homme Profil pro
    Bretagne
    Inscrit en
    Septembre 2005
    Messages
    1 000
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bretagne
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 000
    Par défaut
    Je me demande quel contexte renvoi TRUE dans ce test : if Index = FControlData^.EventCount then !

  4. #4
    Membre expérimenté
    Homme Profil pro
    Consultant fonctionnel
    Inscrit en
    Décembre 2014
    Messages
    109
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Consultant fonctionnel

    Informations forums :
    Inscription : Décembre 2014
    Messages : 109
    Par défaut
    Bjr,
    C'est normal, une boucle for incrémente "Index".
    Si la boucle for va de 0 à Count-1, et si elle termine sa boucle, l'index sera égal à Count et ne sera pas indéfini.
    (sera égal à la valeur du "to" +1, ou du "downto" -1)

  5. #5
    Membre émérite
    Homme Profil pro
    Chef de projets retraité
    Inscrit en
    Juillet 2011
    Messages
    452
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Cher (Centre)

    Informations professionnelles :
    Activité : Chef de projets retraité
    Secteur : Transports

    Informations forums :
    Inscription : Juillet 2011
    Messages : 452
    Par défaut
    Bonjour,

    Citation Envoyé par solilog Voir le message
    Bjr,
    C'est normal, une boucle for incrémente "Index".
    Si la boucle for va de 0 à Count-1, et si elle termine sa boucle, l'index sera égal à Count et ne sera pas indéfini.
    (sera égal à la valeur du "to" +1, ou du "downto" -1)
    J'y crois de moins en moins. La première version du pascal (définie par Wirth) dit que l'index de la boucle est indéfini à la sortie normale de la boucle? Et je n'ai pas vu que le vendeur de DELPHI ait modifié cet état de choses.

    Lorsque un boucle comme celle que tu montres est aussi petite, Un index de boucle peut valoir tout et n'importe quoi à la sortie d'une boucle (sauf en cas de sortie prématurée break par exemple)
    En particulier, selon le niveau d'optimisation ou la version du compilateur, la boucle peut être faite avec un registre et en sortie normale l'index peut valoir à peu près n'importe quoi!

    Lorsque j'ai des choses comme ça à faire, j'utilise en général une variable intermédiaire...

    Cordialement

  6. #6
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 912
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 912
    Par défaut
    Il faudrait voir le contexte général mais je n'écrirais pas ce genre de code.

    • Comment être sûr que l'optimisation n'a pas généré une boucle descendante, index n'étant pas utilisé à l'intérieur de cette boucle ?
    • Si EventCount vaut 0 nous n'entrons pas dans la boucle, que vaut index ?
    • Considérer que si la boucle va à son terme et est ascendante index vaudra ValeurMax +1 ne pourrait être "valide" que si cette valeur max est inférieure au high du type, sinon elle vaudra 0 si non signée ou une valeur négative.


    Grosse prise de tête en perspective pour pas grand chose à mon avis, surtout qu'ici on connait pertinemment le nombre max de pas et donc le pointeur PID max, on pourrait tester son dépassement

  7. #7
    Membre chevronné Avatar de der§en
    Homme Profil pro
    Bretagne
    Inscrit en
    Septembre 2005
    Messages
    1 000
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bretagne
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 000
    Par défaut
    Basiquement, j’utiliserais un booléen initialisé avant la boucle pour être certain de la valeur à sa sortie.

  8. #8
    Membre expérimenté
    Homme Profil pro
    ‫‬
    Inscrit en
    Septembre 2024
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : ‫‬

    Informations forums :
    Inscription : Septembre 2024
    Messages : 144
    Par défaut
    Je pense qu'avec une variable de type entier les valeurs -1 et Count sont prévisibles très utilisées et qui sont valides pour ce type de donnée, mais For ne travaille pas uniquement avec les entiers, elle peut être une énumération un caractère et dans ce contexte ça devient plus compliqué.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for al :=  Low(TAlign) to High(TAlign) do

  9. #9
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 982
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 982
    Par défaut
    On peut l'écrire ainsi aussi via une sous-fonction, dans ce cas cela fonctionne et les IndexOf dans Classes.pas sont codé ainsi

    Je ne suis pas fan du Break, je fais plutôt des sous-fonction avec Exit, surtout qu'au final le nom de la fonction donne un sens à la boucle
    Mais je ne savais pas que Break autorisait la même astuce d'utilisation du compteur que le Exit.

    Vu que c'est dans TDelegatedOleControl.GetEventMethod, un code officiel Delphi, c'est intéressant, cependant le code compilé doit être sa version ASM et non le code Pascal
    D'ailleurs le code Pascal correspond à la version ASM32, la version 64 a totalement été repensée.

    Citation Envoyé par exoseven Voir le message
    le compteur est dans un état indéterminé à la fin de la boucle sauf après un break ou un exit, mais le code me parait quand même bancal
    Si on lit le code, en fait cela teste justement le cas où il n'y a pas eu de Break puisque Index dépasse la value maximum de la liste

    Citation Envoyé par der§en Voir le message
    Je me demande quel contexte renvoi TRUE dans ce test : if Index = FControlData^.EventCount then !
    C'est lorsque la boucle n'a rien trouvé et donc c'est terminé jusqu'à dépasser la valeur max


    Si l'on isole les variables locales uniquement utilisés par la boucle qui commence la fonction TDelegatedOleControl.GetEventMethod cela donne
    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 IndexOfPID(): Integer;
      var
        PID: ^LongInt;
      begin
        PID := FControlData^.EventDispIDs;
        for Result := 0 to FControlData^.EventCount-1 do
        begin
          if DispID = PID^ then
            Exit;
     
          Inc(PID);
        end;
     
        Result := -1;
      end;
    et donc

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
     
      Index := IndexOfPID();
      if Index < 0 then
      begin
        Method.Code := nil;
        Method.Data := nil;
        Exit;
      end;
    C'est plus long mais clairement on comprend mieux l'intention du code
    Si l'on trouve pas le DispID dans la table des functions, cela retourne aucune méthode


    d'ailleurs les Assert qui suivent ... franchement, cela sent un peu le code expérimental d'un dev qui a voulu s'amuser

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
      Assert(Index >= 0);
      Assert(Index < FControlData^.EventCount);
    Si un jour le compilateur ne réagit plus de la même façon, les Assertions informeront le développeur de l'anomalie mais on ressent donc le doute dans cette façon de faire
    Et puis, comme je le disais, normalement c'est uniquement le code ASM qui est réellement utilisé
    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

  10. #10
    Membre expérimenté
    Homme Profil pro
    ‫‬
    Inscrit en
    Septembre 2024
    Messages
    144
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Autre

    Informations professionnelles :
    Activité : ‫‬

    Informations forums :
    Inscription : Septembre 2024
    Messages : 144
    Par défaut
    D'ailleurs le code Pascal correspond à la version ASM32, la version 64 a totalement été repensée.
    En D7 cette fonction n'est disponible qu'en ASM comme pas mal d'autres ce n'est que dans les versions ultérieures de Delphi que les versions Pure Pascal sont possibles

    La première fois que j'ai rencontré cette avertissement c'était dans une fonction de recherche de texte un peu comme ceci:
    cette version (break) n'émet pas l'avertissement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function TForm1.IdxOf(const Name:string): integer;
    begin
      for Result := ControlCount-1 downto 0 do
        if Controls[Result].Name = Name then
            break; 
    end;
    la version Exit émet l'avertissement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    function TForm1.IdxOf(const Name:string): integer;
    begin
      for Result := ControlCount-1 downto 0 do
        if Controls[Result].Name = Name then
            exit;
    end;

  11. #11
    Membre chevronné Avatar de der§en
    Homme Profil pro
    Bretagne
    Inscrit en
    Septembre 2005
    Messages
    1 000
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Bretagne
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2005
    Messages : 1 000
    Par défaut
    Merci pour l’astuce d’utiliser Result dans un for, je n’y avait jamais pensé

  12. #12
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 982
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    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 982
    Par défaut
    C'est écrit comme cela depuis longtemps dans les fonctions IndexOf dans Classes.pas, autant imiter ceux qui ont créé Delphi, perso, je le pratique depuis toujours et cela ne pose aucun soucis

    Pour moi, la façon correcte de l'écrire c'est ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    function TForm1.IdxOf(const Name:string): integer;
    begin
      for Result := ControlCount - 1 downto 0 do
        if Controls[Result].Name = Name then
          Exit;
     
      Result := -1;
    end;
    Pas d'avertissement et cela évite tout doute sur l'élément non trouvé ou liste vide, tous les IndexOf dans Classes.pas sont écrits ainsi (à part que c'est plutôt en Inc qu'en Dec mais c'est un détail, quoi que la comparaison à Zéro est plus rapide que la Comparaison à N)
    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

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

Discussions similaires

  1. [Python 2.X] Décomposition de variable après une boucle for
    Par Clovis78 dans le forum Général Python
    Réponses: 2
    Dernier message: 21/12/2020, 20h51
  2. [MySQL] lecture en boucle for après mysql_fetch_array
    Par SmileAndFly dans le forum PHP & Base de données
    Réponses: 7
    Dernier message: 30/01/2009, 13h47
  3. Variables de session dans une boucle for
    Par lavande4 dans le forum Langage
    Réponses: 1
    Dernier message: 25/10/2008, 14h33
  4. Gérer mes variables après une boucle
    Par Snipy dans le forum Langage
    Réponses: 10
    Dernier message: 06/05/2008, 12h09
  5. [RegEx] problème variable au sein d'une boucle for
    Par mussara dans le forum Langage
    Réponses: 4
    Dernier message: 22/06/2006, 14h26

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