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 :

Déclaration d'entier: Respecter le type exact ?


Sujet :

C++

  1. #1
    Membre habitué Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Points : 177
    Points
    177
    Par défaut Déclaration d'entier: Respecter le type exact ?
    Bonjour,

    J'aurais une question d'ordre général en ce qui concerne les
    déclaration d'entier short, long, signé, non signé etc..

    Très souvent dans les exemples des livres ou sur le net les
    entiers sont généralement déclaré par un simple int, même si la variable
    ne doit contenir qu'un tout petit nombre non signé.
    J'ai donc pris l'habitude de déclarer un int dès que j'ai besoin de stocker un entier.
    Mais ce qui m'a fait tiquer c'est que lorsque j'utilise un vector de la stl par ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for(int i = 0; i < monVecteur.size(); i++)
    Le compilo me met un avertissement à cause de la comparaison entre un int
    et un unsigned int (retourné par la méthode size).
    J'ai aussi quelques avertissements du même genre avec certaines librairies
    où le compilo est très pointilleux sur les types de retour.

    Aussi, j'aimerais bien me fixer une règle et m'y tenir.
    Alors est ce qu'il vaut mieux respecter scrupuleusement le type
    de valeur attendue: déclarer un unsigned char pour un petit nombre non signé,
    un short int pour un nombre signé plus important etc... ou bien
    mettre des int partout en espérant que le compilo ne se plaindra pas trop ?
    Et est ce que cela fait gagner de l'espace mémoire (et éventuellement de la vitesse) ?


    Merci d'avance.

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Au lieu d'écrire ce genre de boucles, fais plutôt une boucle foreach.

  3. #3
    Membre habitué Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Points : 177
    Points
    177
    Par défaut
    Je ne connaissais pas le foreach en C++, c'est bon à savoir.
    Mais ça ne répond pas vraiment à ma question.

  4. #4
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par tintin72 Voir le message
    J'ai donc pris l'habitude de déclarer un int dès que j'ai besoin de stocker un entier.
    Sage habitude, int est l'abréviation de integer, c-a-d entier en français.

    Mais ce qui m'a fait tiquer c'est que lorsque j'utilise un vector de la stl par ex:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    for(int i = 0; i < monVecteur.size(); i++)
    Le compilo me met un avertissement à cause de la comparaison entre un int
    et un unsigned int (retourné par la méthode size).
    Il existe des solutions pour palier à cela. Pour ma part je caste systématiquement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(int i = 0; i < int(monVecteur.size()); i++)
    Je trouve cela plus avantageux que d'utiliser des entiers non-signés, dont le maniement est plus dangereux, surtout comme indices. Le dernier bug auquel j'ai été confronté avec eux, par exemple, c'était une fonction de ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void f(size_t first, size_t last)
    {
      for(size_t i = first; i <= last; ++i) {...}
    }
    A priori rien de bien méchant. A part qu'à un moment j'ai eu besoin d'inverser la boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void f(size_t first, size_t last)
    {
      for(size_t i = last; i >= first; ++i) {...}
    }
    Et là boum, l'appel f(0, x) donne une boucle infinie, ce qui n'est pas évident de voir du premier coup, dans le feu de l'action d'une opération de maintenance urgente.

    Alors est ce qu'il vaut mieux respecter scrupuleusement le type
    de valeur attendue: déclarer un unsigned char pour un petit nombre non signé, un short int pour un nombre signé plus important etc... ou bien
    mettre des int partout en espérant que le compilo ne se plaindra pas trop ?
    Et est ce que cela fait gagner de l'espace mémoire (et éventuellement de la vitesse) ?
    Personnellement, j'utilise int partout où j'ai besoin d'un entier sauf :
    - Si j'ai une grande quantité de données à stoker (à partir de quelques millions, typiquement), j'utilise si possible un type plus petit pour diminuer l'espace mémoire et le temps d'accès. En dehors de ça, utiliser un type plus petit risque au contraire de ralentir, int est en général le type entier le plus rapide, car correspondant à la taille des registres du processeur.
    - Si INT_MAX risque d'être trop petit, j'utiliserai un type plus grand
    - Pour manipuler des bits, j'utiliserai unsigned car les opérations bit-à-bit y son mieux définies

  5. #5
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 281
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 281
    Points : 11 029
    Points
    11 029
    Par défaut
    size() retourne un container<>::size_type. Soit tu utilises ce type, soit tu triches en utilisant size_t, soit tu attends le C++0x pour utiliser auto.

    Personnellement, je préfère utiliser le type officiellement retourné.

  6. #6
    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
    Salut,

    De prime abord, il n'est simplement "pas logique" de vouloir déclarer un entier dont tu sais pertinement que la valeur tiendra dans un char (ou dans un short) sous la forme d'un int...

    De la même manière, pourquoi aller perdre toute la partie des valeurs révolues aux nombre négatifs, si tu sais que, quoi qu'il arrive, ta valeur ne sera jamais inférieure à 0

    En cela, l'idéal reste quand même toujours de veiller à utiliser le type "le plus adéquat" pour tes variables de type entier.

    Cela, c'est pour la partie qui porte sur la pure réflexion par rapport à la situation.

    En effet, il n'est pas rare de constater qu'une valeur à la base représentée par un caractère puisse être "promue", du fait de l'implémentation du compilateur, en un int car c'est "le type le plus adapté à l'utilisation des registres du processeur"...
    Citation Envoyé par Sylvain Togni Voir le message
    Sage habitude, int est l'abréviation de integer, c-a-d entier en français.
    int est bel et bien l'abréviation de "integer", mais, il n'empeche qu'il ne sert finalement pas à grand chose de prévoir une valeur pouvant aller jusqu'à 2 milliards là où la valeur maximale attendue ne serait que 255 ou seize milles et quelques...
    Il existe des solutions pour palier à cela. Pour ma part je caste systématiquement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for(int i = 0; i < int(monVecteur.size()); i++)
    Je trouve cela plus avantageux que d'utiliser des entiers non-signés, dont le maniement est plus dangereux, surtout comme indices.
    Et tu as bien tord...

    Justement, l'utilisation d'un entier non signé lorsqu'il s'agit de manipuler des incide et largement plus sécuritaire que celle d'entiers non signés...
    En effet, si tu as un tableau "C style" classique, la variable représente l'adresse du premier élément du tableau (celui d'indice 0), et toute tentative d'acces à l'indice "-1" peut mener à des conséquences facheuses.

    N'oublie pas, en outre, que les valeurs d'indices sont d'office considérées comme des valeurs non signées, et que, dans le cas d'une architecture x86, les entiers négatifs sont traités selon le principe du complément à deux...
    Le dernier bug auquel j'ai été confronté avec eux, par exemple, c'était une fonction de ce genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void f(size_t first, size_t last)
    {
      for(size_t i = first; i <= last; ++i) {...}
    }
    A priori rien de bien méchant. A part qu'à un moment j'ai eu besoin d'inverser la boucle
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void f(size_t first, size_t last)
    {
      for(size_t i = last; i >= first; ++i) {...}
    }
    Et là boum, l'appel f(0, x) donne une boucle infinie, ce qui n'est pas évident de voir du premier coup, dans le feu de l'action d'une opération de maintenance urgente.
    Ce n'est pas parce qu'une manipulation effectuée distraitement t'a un jour posé problème que tu dois décider de te passer, justement, de l'intérêt des entiers signés...

    A la limite, j'ai même envie de dire que le fait d'utiliser des entiers non signés n'arrange rien dans ce cas... tout au plus "gagne" tu la moitié des itérations avant de te rendre compte que tu a "foiré" ta boucle.

    Dis toi bien que, si la norme a décidé d'utiliser des entiers non signés comme type de retour des méhodes size(), ce n'est vraiment pas sans raison...

    Entre autre le fait que, ainsi que je l'ai signalé, il n'est pas "sémantiquement correct" d'avoir une taille négative, sans oublier le fait que, comme il s'agit (à peu de chose près) de la valeur maximale admisible pour un entier, cela permet d'éviter les limitations qui seraient induites par l'utilisation de types permettant de représenter des valeurs moindres
    Personnellement, j'utilise int partout où j'ai besoin d'un entier sauf :
    - Si j'ai une grande quantité de données à stoker (à partir de quelques millions, typiquement), j'utilise si possible un type plus petit pour diminuer l'espace mémoire et le temps d'accès. En dehors de ça, utiliser un type plus petit risque au contraire de ralentir, int est en général le type entier le plus rapide, car correspondant à la taille des registres du processeur.
    - Si INT_MAX risque d'être trop petit, j'utiliserai un type plus grand
    - Pour manipuler des bits, j'utiliserai unsigned car les opérations bit-à-bit y son mieux définies
    Là, je suis effectivement d'accord avec toi...

  7. #7
    Membre habitué Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Points : 177
    Points
    177
    Par défaut
    De prime abord, il n'est simplement "pas logique" de vouloir déclarer un entier dont tu sais pertinement que la valeur tiendra dans un char (ou dans un short) sous la forme d'un int...
    Tout à fait d'accord, c'est d'ailleur ce raisonnement qui m'a
    incité à créer ce topic.
    En ce qui concerne les indices et indexation de tableaux containers etc...
    cela me semble logique d'utiliser des unsigned int. En effet, un tableau
    ou container ne peut pas contenir -1 élément, ça n'a pas de sens.

    Donc en résumé en conclusion on pourrait dire:
    Utiliser des entiers non signés pour les indices et indexation (tableaux containers etc...).
    Respecter le type de valeur de retour des méthodes/fonctions.

    Maintenant comment savoir dans quelle situation un int sera plus adapté à l'utilisation
    des registres du processeur ?

  8. #8
    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
    A titre personnel (ce qui signifie qu'il est largement admis de ne pas être d'accord avec moi, et que les arguments peuvent être tout à fait compréhensible), je me dis que, si même il devait effectivement s'avérer qu'un int est plus efficace à l'utilisation - au niveau du processeur - qu'un short ou un char, la "perte de performance" est suffisemment petite, surtout quand on voit les capacités des ordinateurs actuels, pour ne pas commencer à entrer dans ces considérations.

    J'entends par là que, comme tu le sais sans doute, dans 90% des cas, l'optimisation prématurée est le chemin vers l'enfer.

    Le fait de commencer à changer le type d'une variable dont tu sais que la valeur maximale tiendrait dans un type "char" fait clairement partie de ce que l'on peut définir comme une "optimisation prématurée".

    Avant de prendre cette décision, il y a donc déjà lieu de veiller à utiliser l'algorithme le plus efficace possible, et, si *vraiment* les performances doivent encore être améliorées, il sera toujours temps de trouver le point précis où appliquer l'optimisation basée sur le type de la variable.

    En effet, il est courant de dire que "90% du temps est utilisé par 10% du code" (les chiffres peuvent varier, mais l'expression est ainsi faite), et donc, si les performances, malgré les capacités du matériel ne sont pas à la hauteur de ce que l'on attend, il sera toujours temps de faire un "audit" des performances après avoir optimisé tous les algorithmes qui pouvaient l'être et de décider en connaissance de cause que telle ou telle variable serait plus judicieusement représentée sous la forme d'un int au lieu d'un short.

    Car il ne faut pas oublier une chose qui se vérifie tous les jours: un code est beaucoup plus souvent lu qu'il n'est écrit/compilé.

    Le fait d'utiliser un char ou un short pour représenter une valeur numérique a cet énorme avantage d'être "auto commenté" quant aux valeurs admissibles.

    Et ca, c'est en mesure d'aider le lecteur du code à se rendre compte que le fait de donner la valeur 1000000 à une variable n'est pas opportun

  9. #9
    Membre habitué Avatar de tintin72
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    663
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 663
    Points : 177
    Points
    177
    Par défaut
    Dans l'ensemble je suis tout à fait d'accord avec toi.
    Cela dit je crois que le pb vient aussi d'un syndrome dont je suis moi même
    atteint: La flemme.
    C'est vrai qu'écrire à chaque fois unsigned et choisir le type approprié
    devient rapidement contraignant alors qu'il est si simple de mettre un int.
    Mais comme je l'ai dis plus haut, dans la majorité des cas (livres, tutoriaux etc..)
    c'est le int qui prédomine.
    Toutefois, je suppose que si mettre des int partout posait vraiment des pb, certains
    programmeurs auraient réagis et lancé des débats mais je n'ai rien vu de tel.

    C'est vrai qu'il n'y a que dans du (vieux) code en C où j'ai vu que chaque type de variable
    était soigneusement choisi en fonction du résultat attendu.
    Etait ce peut être parce qu'à l'époque la mémoire valait son pesant de cacahuètes
    et qu'un programmeur ne pouvait pas se permettre de gaspiller un int alors
    qu'un unsigned char suffisait ?

    En tout cas j'avoue que je ne sais toujours pas quelle attitude adopter par rapport à tout ça.
    Cela mériterait presqu'un débat:
    L'optimisation des registres (à vérifier) et la simplicité d'un coté, et de l'autre la logique
    la rigueur et l'"auto commentaire".

    Le sujet reste ouvert.

  10. #10
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par koala01 Voir le message
    De prime abord, il n'est simplement "pas logique" de
    vouloir déclarer un entier dont tu sais pertinement que la valeur tiendra
    dans un char (ou dans un short) sous la forme d'un int...
    C'est un point de vue sur lequel il y a deux écoles (peut-être plus, je en
    suis pas sûr que les choix sur la pertinence d'utiliser des types plus
    petits hors stockage soit fortement lié avec les choix sur la pertinence
    d'utiliser les types non signés dès que les valeurs négatives sont
    absentes). Nier l'existence des autres ou que leur point de vue est
    raisonnable ne change rien au fait (comme pour 0 par rapport à NULL, ou
    comme -- beaucoup plus polémique encore -- le cast du résultat de malloc()
    en C).


    Le langage me semble fortement biaisé vers l'utilisation de int, par
    exemple dans
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    short a, b, c;
    c = a + b;
    l'addition qui est faite est une addition de int. Et donc
    l'utilisation de char et short comme types entiers est une
    optimisation en espace (je ne parle donc pas de char pour les caractères)
    et donc en dehors des structures de stockage c'est généralement une erreur
    (tout comme pour float pour les types flottants d'ailleurs). Nous ne
    sommes pas en Ada ou en Pascal (langages dans lesquels je vais utiliser
    beaucoup plus de types différents) qui ont des types à intervalles
    contraints.


    Quant aux types non signés, c'est un peu le même problème. Les règles du
    langages les favorisent et dès qu'on a des expressions où les deux
    apparaissent, on se retrouve trop souvent avec un résultat non signé quand
    on le voulait signé. Je préfère donc garder des variables signées autant
    que possible. Mais ici il faut tenir compte que la bibliothèque semble
    avoir été écrite par des gens d'une école autre que celle de ceux ayant
    définis le langage (étant donné le recoupement, c'est vraisemblablement une
    question de compromis et de considérations pragmatiques, par exemple le
    désir de garder size_t à 16 bits sur X86 en dehors du mode huge), et ma
    tendance est d'utiliser tant que ce peut les types déclarés (pratique qui
    ne fera vraisemblablement que s'amplifier avec auto).


    N'oublie pas, en outre, que les valeurs d'indices sont
    d'office considérées comme des valeurs non signées,
    Depuis quand? J'ai souvent utilisé pt[-1] avec l'effet voulu -- et garanti
    quelle que soit l'architecture.

    et que, dans le cas d'une architecture x86, les entiers négatifs
    sont traités selon le principe du complément à deux...
    En quoi les caractéristiques du x86 ont un rapport avec le sujet?

    Ce n'est pas parce qu'une manipulation effectuée distraitement t'a
    un jour posé problème que tu dois décider de te passer, justement, de
    l'intérêt des entiers signés...
    Un des problèmes, c'est pas les entiers signés, c'est les entiers non
    signés.

    A la limite, j'ai même envie de dire que le fait d'utiliser des
    entiers non signés n'arrange rien dans ce cas... tout au plus "gagne" tu la
    moitié des itérations avant de te rendre compte que tu a "foiré" ta
    boucle.
    Tu n'as pas vu le problème. Il a écrit une boucle infinie. x >= 0 est
    toujours vrai pour x non signé.

  11. #11
    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 Jean-Marc.Bourguet Voir le message
    Tu n'as pas vu le problème. Il a écrit une boucle infinie. x >= 0 est
    toujours vrai pour x non signé.
    Effectivement, je ne l'avais pas bien appréhendé...

    Mais je pense que c'est surtout symptômatique d'un problème récurrent en programmation qui est la récupération de quelque chose qui fonctionne dans un but "d'adaptation" quand il est associé avec une faute d'attention, et dont l'histoire informatique est jalonnée des catastrophes que le phénomène a pu provoquer.

    Si tout le monde est bel et bien convaincu (du moins, je l'espère ) de la nécessité d'être attentif lorsque l'on implémente un algorithme, il arrive (encore) trop souvent que des gens se basent sur le principe que "ca marche très bien ainsi" pour profiter de cette extraordinaire invention qu'est le "copier / coller" à des fins d'adaptations sans avoir pris la précaution élémentaire de s'assurer que la logique est cohérente...

  12. #12
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Un char c'est moins performant qu'un int hein...

    Le truc c'est qu'en pratique, toutes les boucles qu'on veut faire ce sont vraiment des foreach, donc on a jamais besoin d'écrire des boucles dangereuses avec des indices...

  13. #13
    Membre éclairé Avatar de HanLee
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    738
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France, Rhône (Rhône Alpes)

    Informations forums :
    Inscription : Mai 2004
    Messages : 738
    Points : 871
    Points
    871
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Un char c'est moins performant qu'un int hein...

    Le truc c'est qu'en pratique, toutes les boucles qu'on veut faire ce sont vraiment des foreach, donc on a jamais besoin d'écrire des boucles dangereuses avec des indices...
    +1

    C'est comme la récursion dans les langages fonctionnels, en pratique on ne s'en sert quasiment jamais, on a tout ce qu'il faut avec les fonctions d'ordre supérieur qui réalisent des itérations, for_each, iter, map (~ std::transform) fold_left (~ std::accumulate)...

  14. #14
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Un autre avantage des signés c'est en terme de vérification. Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    void fonctionQuiPrendUnEntierPositif(int i)
    {
      assert(i >= 0);
      ...
    }
    L'appel fonctionQuiPrendUnEntierPositif(-1) génèrera une assertion. La même chose avec un paramètre non-signé compilera et s'exécutera sans avertissement. La programmation par contrat, gage de robustesse, est plus difficile avec les non-signés (de même qu'avec l'usage des types plus petits d'ailleurs).

    L'usage de ces types serait intéressante si des vérifications automatiques étaient effectuées sur leur domaine de valeurs.

    Citation Envoyé par loufoque Voir le message
    Le truc c'est qu'en pratique, toutes les boucles qu'on veut faire ce sont vraiment des foreach, donc on a jamais besoin d'écrire des boucles dangereuses avec des indices...
    Cela dépend du domaine. Je fais de l'informatique scientifique par exemple, j'utilise énormément de boucles avec indices sur des vecteurs. Les écrire avec un foreach ne serait peut-être pas impossible mais serait une perte de lisibilité importante.

  15. #15
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    L'appel fonctionQuiPrendUnEntierPositif(-1) génèrera une assertion. La même chose avec un paramètre non-signé compilera et s'exécutera sans avertissement.
    Je dirais plutôt qu'utiliser un entier non signé permet de faire en sorte que le cas n'arrive jamais, éliminant le besoin de faire des assertions qui a priori ne sont activés que lors du débogage.
    Ça te permet d'utiliser le typage pour assurer ta précondition au lieu de l'asserter, puisque le type "entier non signé" maintient l'invariant que celui-ci est toujours non signé.
    Après le risque c'est qu'un entier non signé peut être construit avec un type signé, mais ce n'est pas vraiment un problème et même si ça en est un il suffit d'utiliser un type non signé maison qui ne peut pas être construit à partir d'un entier signé.

    Les écrire avec un foreach ne serait peut-être pas impossible mais serait une perte de lisibilité importante.
    Tout dépend des outils que tu utilises. Avec des adapteurs de séquence, tu peux faire très élégamment des filtrages, filtrages adjacents, transformations, génération automatique d'éléments (en fonction des éléments précédents ou non) et inversement de séquence, le tout en même temps. Franchement, ça couvre quasiment tout ce qu'on veut faire, sauf algorithmes de type algorithme de tri, qui de toutes façons devraient avoir droit à leur propre fonction générique et donc ne pas être une boucle "utilisateur".

  16. #16
    Membre éclairé

    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    717
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 717
    Points : 858
    Points
    858
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Je dirais plutôt qu'utiliser un entier non signé permet de faire en sorte que le cas n'arrive jamais
    Ah bon ? Tu veux dire que l'appel fonctionQuiPrendUnEntierPositif(-1) n'arrivera jamais si le paramètre est déclarer non-signé !? Moi je ne voit pas la différence, à part que dans le cas non-signé c'est plus difficile à detecter.

    éliminant le besoin de faire des assertions qui a priori ne sont activés que lors du débogage.
    1) j'ai pris l'exemple d'une assertion pour vérifier le contrat mais c'est la même chose avec tout autre système de report d'erreur.
    2) Je ne comprend vraiment pas en quoi utiliser des non-signés à la place de signé permet de se passer de vérifications vu que le compilateur n'en effectue aucune automatiquement.

    Ça te permet d'utiliser le typage pour assurer ta précondition au lieu de l'asserter, puisque le type "entier non signé" maintient l'invariant que celui-ci est toujours non signé.
    Non, le type "entier non signé" ne maintient rien du tout en C++, ce n'est en général qu'une interprétation particulière d'une séquence de bits, cela permet au mieux de déplacer le problème ailleurs.

    Après le risque c'est qu'un entier non signé peut être construit avec un type signé,
    Oui, et pas seulement. Par exemple l'appel fonctionQuiPrendUnEntierPositif(i - j) avec i < j déclenchera l'assertion dans le cas signé, pas dans le cas non-signé.

    mais ce n'est pas vraiment un problème
    Ah bon ?

    et même si ça en est un il suffit d'utiliser un type non signé maison qui ne peut pas être construit à partir d'un entier signé.
    Là d'accord, mais il n'était pas question de ça au départ.

  17. #17
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    La fonction prend un entier non signé. L'entier ne peut donc jamais être négatif, donc pas de problème.

    L'appelant appelle la fonction avec un entier signé, qui est converti implicitement en un entier non signé. C'est sa faute s'il ne s'en rend pas compte, et c'est tout. S'il pense ne pas être sûr de pouvoir faire attention, il a qu'à utiliser un type convertible uniquement explicitement.
    L'appel à la fonction sera toujours valide, sauf que la valeur utilisée ne sera pas celle attendue.

    1) j'ai pris l'exemple d'une assertion pour vérifier le contrat mais c'est la même chose avec tout autre système de report d'erreur.
    C'est une erreur de programmation, les assertions sont le seul bon système à utiliser ici.

    2) Je ne comprend vraiment pas en quoi utiliser des non-signés à la place de signé permet de se passer de vérifications vu que le compilateur n'en effectue aucune automatiquement.
    Un entier non signé maintient l'invariant qu'à tout moment, il est non signé. Donc il est garanti que celui-ci est non signé, quoi qu'il arrive.

    Oui, et pas seulement. Par exemple l'appel fonctionQuiPrendUnEntierPositif(i - j) avec i < j déclenchera l'assertion dans le cas signé, pas dans le cas non-signé.
    Avec des entiers non signés, ça va juste faire un overflow. Tu crois peut-être qu'utiliser un entier signé te protège de ces problèmes ?
    Ça reste rien de grave, puisque la fonction reçoit toujours un entier positif, qui est ce qu'elle attend. Ce n'est peut-être pas ce que l'utilisateur attend, mais c'est sa faute s'il n'a pas fourni l'entrée qu'il voulait...

  18. #18
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par loufoque Voir le message
    Avec des entiers non signés, ça va juste faire un overflow.
    Non. Les entiers non signés sont des types modulaires pour lequel il n'y a pas d'overflow par définition.

    Je comprends -- même si je n'adhère pas -- qu'on puisse vouloir les utiliser pour autre chose comme un substitut d'un type contraint inexistant, mais il ne faut quand même pas oublier la nature de ces types.

    Tu crois peut-être qu'utiliser un entier signé te protège de ces problèmes ?
    Que le paramètre soit signé ou pas, le problème est là et le responsable est l'utilisateur. S'il est signé, il est possible de faire une assertion, s'il ne l'est pas, non. Si la nature du problème ne demande pas un type modulaire et si doubler l'intervalle des valeurs possibles n'est pas important, utiliser un entier signé est un choix valide.

  19. #19
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 381
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

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

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 381
    Points : 41 582
    Points
    41 582
    Par défaut
    Je plussoie Jean-Marc. Contrôler qu'un entier reçu en paramètre est positif est plus facile et plus lisible que de contrôler qu'un entier non-signé n'est pas dans l'intervalle (INT_MAX, UINT_MAX)...

  20. #20
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Il n'y a pas à contrôler que l'entier non signé soit dans cet intervalle, c'est un intervalle de valeurs parfaitement valide pour la fonction.

    La fonction fonctionne avec n'importe quel entier positif. Faire en sorte qu'elle ne puisse recevoir QUE des entiers positifs (bref, que des valeurs dans le domaine pour lequel elle fonctionne) permet de garantir qu'elle fonctionne tout le temps et qu'il n'y a pas de vérification à faire.

Discussions similaires

  1. Réponses: 3
    Dernier message: 30/09/2014, 20h37
  2. [XL-2007] Respecter un format exact de cellule à rechercher
    Par neoinfo dans le forum Macros et VBA Excel
    Réponses: 12
    Dernier message: 30/05/2013, 12h01
  3. Types entiers génériques et Types entiers fondamentaux
    Par Vilukariok dans le forum Langage
    Réponses: 11
    Dernier message: 21/06/2011, 09h37
  4. un like d'un type entier avec un type string.
    Par charrynsasi dans le forum VB.NET
    Réponses: 2
    Dernier message: 10/11/2009, 11h13
  5. Réponses: 13
    Dernier message: 25/10/2006, 16h17

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