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

Affichage des résultats du sondage: Pour représenter des entiers positifs en C++, préférez-vous les entiers signés ou non signés ?

Votants
20. Vous ne pouvez pas participer à ce sondage.
  • Je préfère les entiers signés.

    6 30,00%
  • Je préfère les entiers non signés.

    14 70,00%
  • Pas d'avis.

    0 0%
C++ Discussion :

C++ : entiers signés VS entiers non signés


Sujet :

C++

  1. #1
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut C++ : entiers signés VS entiers non signés
    Pour représenter des entiers positifs, la STL utilise des entiers non signés. Par exemple, la fonction std::vector::operator[] prend en paramètre un entier non signé.

    Qt, par contre, utilise int. Par exemple, la fonction QVector::operator[] prend en paramètre un int.
    Le Google C++ Style Guide s'oppose aussi aux entiers non signés (lire la section "Integer_Types").

    La raison invoquée par le Google C++ Style Guide est la suivante :
    Consider:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    for (unsigned int i = foo.Length()-1; i >= 0; --i) ...
    This code will never terminate! Sometimes gcc will notice this bug and warn you, but often it will not. Equally bad bugs can occur when comparing signed and unsigned variables. Basically, C's type-promotion scheme causes unsigned types to behave differently than one might expect.

    So, document that a variable is non-negative using assertions. Don't use an unsigned type.
    D'un autre côté, utiliser des entiers non signés permet de réduire le nombre de contrôles quand un entier doit être positif.
    Par exemple, voici un code utilisant uniquement des entiers signés :
    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
    void f(int integer)
    {
        if(integer >= 0) {
            g(integer);
        } else {
            // code A
        }
    }
     
    void g(int nonNegativeInteger)
    {
        assert(nonNegativeInteger >= 0);
        thowIfNegative(nonNegativeInteger);
        // code B
        h(nonNegativeInteger);
        // code C
    }
     
    void h(int nonNegativeInteger)
    {
        assert(nonNegativeInteger >= 0);
        thowIfNegative(nonNegativeInteger);
        // code D
    }
    Voici le même code utilisant des entiers non signés pour les entiers toujours positifs :
    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
    void f(int integer)
    {
        if(integer >= 0) {
            const size_t castedInteger = checkedConvert<size_t>(integer);
                // check if integer >= 0
                // thow exception if integer > SIZE_MAX
            g(castedInteger);
        } else {
            // code A
        }
    }
     
    void g(size_t integer)
    {
        // code B
        h(integer);
        // code C
    }
     
    void h(size_t integer)
    {
        // code D
    }
    D'ailleurs, pour ceux que ça intéresse, voici mon code de checkedConvert :
    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
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    // Version de g++ : 6.1.0
     
    #include <cassert>
    #include <limits>
    #include <sstream>
    #include <stdexcept>
    #include <typeinfo>
    #include <type_traits>
     
    /*!
     * \brief     Convert signed integer to another signed integer type.
     * \exception std::overflow_error  param is too big   to be convertible to ResultT.
     * \exception std::underflow_error param is too small to be convertible to ResultT.
     */
    template<class ResultT, class ParamT,
        typename std::enable_if<
            std::is_integral<ResultT>::value &&
            std::is_integral<ParamT >::value &&
            std::is_signed  <ResultT>::value &&
            std::is_signed  <ParamT >::value
        >::type* = nullptr
    >
    ResultT checkedConvert(ParamT param)
    {
     #ifndef DO_NOT_CHECK_INTEGER_LIMITS_ON_CONVERSION
        if(param > std::numeric_limits<ResultT>::max()) {
            std::ostringstream streamMessage;
            streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                          << " to "                     << typeid(ResultT).name() << ": "
                          << param << " is too big (maximal allowed value: "
                          << std::numeric_limits<ResultT>::max() << ").";
            throw std::overflow_error(streamMessage.str());
        } else if(param < std::numeric_limits<ResultT>::min()) {
            std::ostringstream streamMessage;
            streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                          << " to "                     << typeid(ResultT).name() << ": "
                          << param << " is too small (minimal allowed value: "
                          << std::numeric_limits<ResultT>::min() << ").";
            throw std::underflow_error(streamMessage.str());
        }
     #endif
        return param;
    }
     
    /*!
     * \brief     Convert nonnegative signed integer to unsigned integer type.
     * \pre       param >= 0
     * \exception std::overflow_error param is too big to be convertible to ResultT.
     * \exception std::domain_error   (in Release mode) param < 0
     */
    template<class ResultT, class ParamT,
        typename std::enable_if<
            std::is_integral<ResultT>::value &&
            std::is_integral<ParamT >::value &&
            !std::is_signed <ResultT>::value &&
             std::is_signed <ParamT >::value
        >::type* = nullptr
    >
    ResultT checkedConvert(ParamT param)
    {
        assert(param >= 0);
        if(param < 0) {
            std::ostringstream streamMessage;
            streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                          << " to "                     << typeid(ResultT).name() << ": "
                          << param << " is negative.";
            throw std::domain_error(streamMessage.str());
        }
     #ifndef DO_NOT_CHECK_INTEGER_LIMITS_ON_CONVERSION
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wsign-compare"
        if(param > std::numeric_limits<ResultT>::max()) {
            std::ostringstream streamMessage;
            streamMessage << "Failure to convert from " << typeid(ParamT) .name()
                          << " to "                     << typeid(ResultT).name() << ": "
                          << param << " is too big (maximal allowed value:"
                          << std::numeric_limits<ResultT>::max() << ").";
            throw std::overflow_error(streamMessage.str());
        }
      #pragma GCC diagnostic pop
     #endif
        return param;
    }
     
    /*!
     * \brief     Convert unsigned integer to another integer type.
     * \exception std::overflow_error param is too big to be convertible to ResultT.
     */
    template<class ResultT, class ParamT,
        typename std::enable_if<
            std::is_integral<ResultT>::value &&
            std::is_integral<ParamT >::value &&
            !std::is_signed <ParamT >::value
        >::type* = nullptr
    >
    ResultT checkedConvert(ParamT param)
    {
     #ifndef DO_NOT_CHECK_INTEGER_LIMITS_ON_CONVERSION
      #pragma GCC diagnostic push
      #pragma GCC diagnostic ignored "-Wsign-compare"
        if(param > std::numeric_limits<ResultT>::max()) {
            std::ostringstream streamMessage;
            streamMessage << "Failure to convert from " << typeid(ParamT).name()
                          << " to " << typeid(ResultT).name() << ": "
                          << param << " is too big (maximal allowed value:"
                          << std::numeric_limits<ResultT>::max() << ").";
            throw std::overflow_error(streamMessage.str());
        }
      #pragma GCC diagnostic pop
     #endif
        return param;
    }
    PS : Rappels :
    • En français, "positif" signifie "positif ou nul" et "négatif" signifie "négatif ou nul".
    • En anglais, "positive" signifie "strictement positif" et "negative" signifie "strictement négatif".


    EDIT 09/10/2016 vers 19h24 : std::runtime_error remplacé par std::range_error et std::logic_error remplacé par std::domain_error.
    EDIT 09/10/2016 vers 19h32 : std::range_error remplacé par std::overflow_error et std::underflow_error.

  2. #2
    Expert confirmé
    Inscrit en
    Mars 2005
    Messages
    1 431
    Détails du profil
    Informations forums :
    Inscription : Mars 2005
    Messages : 1 431
    Points : 4 182
    Points
    4 182
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    La raison invoquée par le Google C++ Style Guide est la suivante :

    [bullshit...]
    Donc la raison number one pour se priver d'un invariant gratuit c'est le parcours inversé ? Ce troll...

    IMHO la seule raison pour se taper du signé tout le temps c'est devoir écrire du code CLI (un autre troll, ça aussi). C'est peut-être d'ailleurs pour cela que cette ineptie se retrouve chez Qt.

    En C, la règle est simple : lorsque l'on a besoin d'un entier signé, on déclare un entier signé (you don't say?). Sinon on utilise size_t ou au pire un unsigned, point barre. J'applique ça aussi à mon code C++ perso.

  3. #3
    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 : 49
    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
    J'ai répondu entiers signé, même si mon avis reste plus nuancé.

    Pour le reste de la discussion, je vais supposer des entiers 32 bits et les signés complément à 2 pour simplifier la discussion, mais le principe reste le même...

    Proximité entre les valeurs courantes et les limites
    En gros, le problème principal des types entiers, c'est qu'ils ne modélisent pas toutes les valeurs possibles de N. Et donc, quand on dépasse les limites, on a des comportements étranges...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<class T>
    void f(T i)
    {
      assert(i < i+1);
    }
    Cet assert n'est pas toujours vrai. Et il sera vrai pour des valeurs différentes pour un int et un unsigned int. Mais dans les deux cas, il sera faux pour des valeurs de i tellement grandes, que si on risque de les rencontrer, il vaudrait mieux de toute manière passer à un type plus long.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<class T>
    void f(T i)
    {
      assert(i > i-1);
    }
    Même chose, cet assert n'est pas toujours vrai. Le problème, c'est qu'avec des unsigned, la valeur pour laquelle il n'est pas vrai est 0. C'est à dire la valeur probablement la plus souvent présente dans le code.

    Du coup, selon le point de vue adopté, ça peut être un argument en faveur des signed ou des unsigned : Soit on fait un programme hyper critique, ultra validé, avec suite de tests quasi exaustive et tout, et dans ce cas là, on préfèrera peut-être les unsigned qui vont plus rapidement mettre en évidence les cas aux limites et permettre de les corriger. Soit on fait du code plus classique, et entre avoir des comportements étranges tous les jours, ou seulement les 29 février des années non bisextiles, on préfèrera utiliser les entiers signés. On va donc dire 1/2 point pour les ints.

    int / unsigned int : 0.5 / 0

    Mode mixte

    On ne peut pas écrire du code sans avoir des entiers signés. Donc, si on a des unsigned, il faudra à un moment mélanger unsigned et signed. Et ce mélange est surprenant pour le moins...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
        int i = -1;
        unsigned int  j = 1;
        if (i<j)
        {
          cout << "On ne passe pas dans ce code..." << endl;
        }
        else 
        {
          cout << "Mais ici... Pas de bol, hein..." << endl;
        }
    Certains compilateurs auront un warning, d'autres pas. Donc comme les opérations mixtes sont casse-gueule, et qu'on ne peut pas raisonnablement imposer de n'utiliser que des unsigned dans un programme, 1 point pour les signed :
    int / unsigned int : 1.5 / 0

    Avec les unsigned, on a de meilleurs invariants
    Je ne suis pas d'accord avec ça. On aurait de meilleurs invariants si les opérations ayant des résultats négatifs n'étaient pas autorisées, causaient une exception ou tout autre mécanisme. Mais ce n'est pas le cas. Ce n'est même pas un comportement indéfini, c'est un comportement défini : unsigned int ne modélise pas des nombres positifs (N), il modélise des nombres compris dans Z/nZ ! C'est ça l'invariant ! Et souvent, le fait que les calculs seront fait par congruence modulo 232, on s'en moque un peu, ce qu'on voudrait, c'est un nombre positif. Pas d'évolution du score...
    int / unsigned int : 1.5 / 0

    Avec les unsigned, on a plus de valeurs possibles quand on représente des nombres positifs
    Oui, 2 fois plus. Mais dans le cas général, si on en est à avoir besoin de représenter des valeurs de cet ordre de grandeur, on est dangereusement proche de la valeur supérieurs de la borne, et il faudrait vraiment penser à prendre un type plus long. Je vais être généreux, 0.25 points pour les unsigned :
    int / unsigned int : 1.5 / 0.25

    Un grand nombre de bibliothèques utilise des unsigned
    Oui, dont par exemple la bibliothèque standard. C'est je pense le meilleur argument en leur faveur. Non pas qu'elles aient forcément raison de faire ainsi, mais simplement parce que pour les utiliser, il vaut mieux faire comme elles (sinon, on augmente les risques liés au fait de mélanger les types). 1 point pour les unsigned.
    int / unsigned int : 1.5 / 1.25


    Conclusion
    On voit que le score est assez serré, surtout à cause du dernier point...
    Quand mon nombre positif représente une grandeur technique, quelque-chose de très proche du langage ou de la bibliothèque standard, je vais avoir tendance à utiliser un unsigned (souvent un size_t), pour des raisons de compatibilité : C'est valable pour un indice dans un tableau, une taille d'objet...
    S'il représente une donnée du monde physique (un âge, un salaire, une note, un nombre de points sur le permis de conduire...), je vais plutôt utiliser des signed int. Éventuellement wrappé dans des classes apportant une sémantique plus appropriée. Par exemple, des intervalles bornés, où si quelqu'un ayant 1 point sur son permis commet une infraction lui en faisant perdre 3, il se retrouve à 0. Pas à -2. Pas à 65534.

    Addendum
    Je ne parlais là que des types représentant une grandeur, une valeur. Si je dois manipuler une donnée pour sa représentation binaire, par exemple pour positionner des sorties sur une carte électronique, ou si on veut appliquer un algorithme d'encryptage, là aucune hésitation, c'est du unsigned qu'il faut utiliser.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 629
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 629
    Points : 10 554
    Points
    10 554
    Par défaut
    Je n'arrive plus à trouver un exemple avec lequel j'ai eu des problèmes (*) , mais par défaut un littéral entier est signé: integer literal



    * -> un test avec un littéral qui échoue

  5. #5
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 115
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 115
    Points : 32 963
    Points
    32 963
    Billets dans le blog
    4
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Un grand nombre de bibliothèques utilise des unsigned
    Oui, dont par exemple la bibliothèque standard. C'est je pense le meilleur argument en leur faveur. Non pas qu'elles aient forcément raison de faire ainsi, mais simplement parce que pour les utiliser, il vaut mieux faire comme elles (sinon, on augmente les risques liés au fait de mélanger les types). 1 point pour les unsigned.
    int / unsigned int : 1.5 / 1.25
    Et ça ne devrait pas influer l'utilisation de int ou unsigned int dans notre code imo : la conversion de int à unsigned est toujours possible, moyennant de tester qu'il n'est pas négatif. Dans l'autre sens on n'est pas assurés de pouvoir assigner la valeur d'un unsigned à un int, elle peut déborder.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  6. #6
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    template<class T>
    void f(T i)
    {
      assert(i < i+1);
    }
    Cet assert n'est pas toujours vrai. Et il sera vrai pour des valeurs différentes pour un int et un unsigned int.
    D'ailleurs, dans le cas des entiers signés, le comportement est indéterminé en cas d'overflow :
    Le compilateur peut optimiser et décider que i < i+1 est toujours vrai.
    Par contre, pour les entiers non signés, le comportement est déterminé en cas d'overflow.

    Exemple :
    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
    // Code compilé ici : http://coliru.stacked-crooked.com/
    // Version de g++ : 6.1.0
    // Commande : g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out
     
    #include <iostream>
    #include <climits>
     
    int main(int argc, char **argv)
    {
        std::cout << "Version de g++ : " << __VERSION__ << "\n\n";
     
        int i = INT_MAX;
        if(i < i+1)
            std::cout << "i < i+1 est vrai selon g++, alors que i == INT_MAX.\n";
        else
            std::cout << "i < i+1 est faux.\n";
     
        const int ci = INT_MAX;
        if(ci < ci+1)
            std::cout << "ci < ci+1 est vrai.\n";
        else
            std::cout << "ci < ci+1 est faux selon g++, qui a détecté l'overflow.\n";
     
        unsigned u = UINT_MAX;
        if(u < u+1)
            std::cout << "u < u+1 est vrai.\n";
        else
            std::cout << "u < u+1 est faux quand u == UINT_MAX.\n";
        return 0;
    }
    Sortie :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    main.cpp: In function 'int main(int, char**)':
    main.cpp:20:15: warning: integer overflow in expression [-Woverflow]
         if(ci < ci+1)
                 ~~^~
    Version de g++ : 6.1.0
     
    i < i+1 est vrai selon g++, alors que i == INT_MAX.
    ci < ci+1 est faux selon g++, qui a détecté l'overflow.
    u < u+1 est faux quand u == UINT_MAX.
    EDIT : Réponse à Bousk :
    Citation Envoyé par Bousk Voir le message
    Et ça ne devrait pas influer l'utilisation de int ou unsigned int dans notre code imo : la conversion de int à unsigned est toujours possible, moyennant de tester qu'il n'est pas négatif. Dans l'autre sens on n'est pas assurés de pouvoir assigner la valeur d'un unsigned à un int, elle peut déborder.
    La STL utilise souvent des entiers non signés dont le nombre de bits peut être plus petit, égal ou plus grand que celui de unsigned.
    Par exemple, std::vector::operator[] prend en paramètre un std::vector::size_type qui est typiquement size_t, mais on ne sait pas si sizeof(size_t) < sizeof(unsigned), sizeof(size_t) == sizeof(unsigned) ou sizeof(size_t) > sizeof(unsigned).

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    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 369
    Points : 41 518
    Points
    41 518
    Par défaut
    Euh, es-tu sûr qu'on n'a pas au moins la garantie que sizeof(size_t) >= sizeof(unsigned)? Ne serait-ce qu'au niveau des limites?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Expert éminent
    Avatar de Pyramidev
    Homme Profil pro
    Développeur
    Inscrit en
    Avril 2016
    Messages
    1 469
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 469
    Points : 6 102
    Points
    6 102
    Par défaut
    Citation Envoyé par Médinoc Voir le message
    Euh, es-tu sûr qu'on n'a pas au moins la garantie que sizeof(size_t) >= sizeof(unsigned)? Ne serait-ce qu'au niveau des limites?
    Dans le draft de C++14, à la section 18.2, il est seulement écrit ceci pour size_t :

    The type size_t is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.
    [Note: It is recommended that implementations choose types for ptrdiff_t and size_t whose integer conversion ranks (4.13) are no greater than that of signed long int unless a larger size is necessary to contain all the possible values.— end note]

  9. #9
    Expert éminent sénior
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 275
    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 275
    Points : 10 985
    Points
    10 985
    Par défaut
    Je préfère utiliser des non signés pour compatibilité avec le standard et l'affirmation d'invariants. Sauf que ... rien n'empêche d'appeler v[-1] et rien ne sera détecté par le compilateur -- c'est dans les commentaires ici (http://ericniebler.com/2014/12/07/a-...f-python-in-c/) que j'ai été correctement exposé au problème pour la première fois. On retrouve tout ça, et plus, dans le post de Loic.

    Le problème, c'est les conversions implicites. Idéalement, il faudrait des types range<T,min,max> avec constructeurs explicites et une arithmétique associée -- pour des invariants de qualité. Cela pourrait se faire assez simplement sur des entiers, mais sur des doubles, c'est très compliqué avec la syntaxe courante (lors d'une expérience récente, je manipulais des range<double, decltype(0_c), decltype(42.5_c)> -- l'objectif était de pouvoir déclarer une fonction qui réalise une opération telle que sqrt(1/x) comme prenant un x de type range<double, decltype(0_excluded), plus_inf_t>.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

Discussions similaires

  1. Des entiers non signés
    Par Gruik dans le forum C
    Réponses: 14
    Dernier message: 13/12/2006, 22h17
  2. Réponses: 9
    Dernier message: 12/10/2006, 00h36
  3. [Fortran 90] Type entier non signé
    Par nnath dans le forum Fortran
    Réponses: 2
    Dernier message: 17/07/2006, 00h21
  4. Déclarer un entier non-signé [PHP]
    Par Bouillou dans le forum Langage
    Réponses: 2
    Dernier message: 17/02/2006, 16h46
  5. [TP] Entier 32 bits non signé
    Par SkaMan dans le forum Turbo Pascal
    Réponses: 6
    Dernier message: 24/08/2005, 22h17

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