68 votes

Pourquoi préférer le langage signé au langage non signé en C++ ?

J'aimerais mieux comprendre pourquoi choisir int plus unsigned ?

Personnellement, je n'ai jamais aimé les valeurs signées, à moins qu'elles n'aient une raison valable. Par exemple, le nombre d'éléments dans un tableau, ou la longueur d'une chaîne de caractères, ou la taille d'un bloc de mémoire, etc. Une telle valeur n'a aucune signification possible. Pourquoi préférer int alors qu'elle est trompeuse dans tous ces cas ?

Je pose cette question parce que Bjarne Stroustrup et Chandler Carruth ont tous les deux conseillé de privilégier l'utilisation de l'Internet. int plus unsigned ici (environ 12:30') .

Je comprends l'argument en faveur de l'utilisation de int plus short o long - int est la largeur de données "la plus naturelle" pour l'architecture de la machine cible.

Mais la différence entre signé et non signé m'a toujours ennuyé. Les valeurs signées sont-elles réellement plus rapides sur les architectures de processeurs modernes ? Qu'est-ce qui les rend plus rapides ?

8voto

vy32 Points 6298

La vitesse est la même sur les architectures modernes. Le problème avec unsigned int est qu'il peut parfois générer des comportements inattendus. Cela peut créer des bogues qui ne seraient pas apparus autrement.

Normalement, lorsque vous soustrayez 1 d'une valeur, celle-ci diminue. Or, avec les deux signed y unsigned int il y aura un moment où la soustraction de 1 créera une valeur BEAUCOUP PLUS GRANDE. La différence essentielle entre unsigned int y int est qu'avec unsigned int la valeur qui génère le résultat paradoxal est une valeur couramment utilisée --- 0 --- alors qu'avec la signature, le nombre est en toute sécurité loin des opérations normales.

En ce qui concerne le retour de -1 pour une valeur d'erreur --- la pensée moderne est qu'il est préférable de lancer une exception plutôt que de tester les valeurs de retour.

Il est vrai que si vous défendez correctement votre code, vous n'aurez pas ce problème, et si vous utilisez religieusement les unsigned partout, tout ira bien (à condition que vous ne fassiez que des additions, et jamais de soustractions, et que vous ne vous approchiez jamais de MAX_INT). J'utilise unsigned int partout. Mais cela demande beaucoup de discipline. Pour de nombreux programmes, vous pouvez vous contenter d'utiliser int et consacrez votre temps à d'autres bugs.

8voto

TemplateRex Points 26447
  1. Utilice int par défaut : il s'intègre mieux dans le reste de la langue

    • L'utilisation la plus courante dans le domaine est l'arithmétique régulière, et non l'arithmétique modulaire.
    • int main() {} // see an unsigned?
    • auto i = 0; // i is of type int
  2. Utiliser uniquement unsigned pour l'arithmétique modulo et la manipulation de bits (en particulier le déplacement)

    • a une sémantique différente de celle de l'arithmétique classique, assurez-vous que c'est ce que vous voulez.
    • le bit-shifting des types signés est subtil (voir les commentaires de @ChristianRau)
    • si vous avez besoin d'un vecteur de plus de 2 Go sur une machine 32 bits, mettez à niveau votre système d'exploitation et votre matériel.
  3. Ne jamais mélanger l'arithmétique signée et non signée

    • Les règles en la matière sont les suivantes compliqué et surprenant (l'un ou l'autre peut être converti en l'autre, en fonction de la taille relative des caractères)
    • allumer -Wconversion -Wsign-conversion -Wsign-promo (gcc est meilleur que Clang ici)
    • la Standard Library s'est trompée avec std::size_t (citation tirée de la vidéo du GN13)
    • utiliser la fourchette si possible,
    • for(auto i = 0; i < static_cast<int>(v.size()); ++i) s'il le faut
  4. N'utilisez pas de caractères courts ou larges à moins que vous n'en ayez réellement besoin

    • le flux de données des architectures actuelles s'adapte bien aux données 32 bits sans pointeur (mais notez le commentaire de @BenVoigt sur les effets de cache pour les types plus petits).
    • char y short économisent de l'espace mais souffrent de promotions intégrales
    • allez-vous vraiment compter jusqu'à la totalité int64_t ?

7voto

Mats Petersson Points 70074

Pour répondre à la question proprement dite : Pour la plupart des choses, cela n'a pas vraiment d'importance. int peut être un peu plus facile à gérer pour des choses comme la soustraction avec le second opérande plus grand que le premier et vous obtenez toujours un résultat "attendu".

Il n'y a absolument aucune différence de vitesse dans 99,9 % des cas, car les SEULES instructions qui diffèrent pour les nombres signés et non signés sont les suivantes :

  1. Allonger le nombre (compléter avec le signe pour les nombres signés ou zéro pour les nombres non signés) - il faut le même effort pour faire les deux.
  2. Comparaisons - un nombre signé, le processeur doit tenir compte du fait que l'un ou l'autre des nombres est négatif ou non. Mais encore une fois, la vitesse est la même pour effectuer une comparaison avec des nombres signés ou non signés - il s'agit simplement d'utiliser un code d'instruction différent pour dire "les nombres dont le bit le plus élevé est défini sont plus petits que les nombres dont le bit le plus élevé n'est pas défini" (en substance). (D'un point de vue pédant, c'est presque toujours l'opération utilisant le RÉSULTAT d'une comparaison qui est différente - le cas le plus courant étant un saut conditionnel ou une instruction de branchement - mais dans tous les cas, il s'agit du même effort, les entrées étant simplement considérées comme signifiant des choses légèrement différentes).
  3. Multiplier et diviser. Il est évident que le signe du résultat doit être converti s'il s'agit d'une multiplication signée, alors qu'une multiplication non signée ne devrait pas changer le signe du résultat si le bit de poids fort de l'une des entrées est activé. Une fois de plus, l'effort est (pour autant que nous le souhaitions) identique.

(Je pense qu'il y a un ou deux autres cas, mais le résultat est le même - peu importe que ce soit signé ou non signé, l'effort pour effectuer l'opération est le même dans les deux cas).

3voto

Kaz Points 18072

En int ressemble davantage au comportement des entiers mathématiques que le type unsigned type.

Il est naïf de préférer le unsigned simplement parce qu'une situation ne nécessite pas la représentation de valeurs négatives.

Le problème est que le unsigned a un comportement discontinu juste à côté de zéro. Toute opération qui tente de calculer une petite valeur négative produit à la place une grande valeur positive. (Pire : une opération définie par l'implémentation).

Des relations algébriques telles que celle-ci a < b implique que a - b < 0 sont détruites dans le domaine non signé, même pour de petites valeurs comme a = 3 y b = 4 .

Une boucle descendante comme for (i = max - 1; i >= 0; i--) ne prend pas fin si i est rendu non signé.

Les bizarreries non signées peuvent causer un problème qui affectera le code, que celui-ci s'attende ou non à ne représenter que des quantités positives.

L'avantage des types non signés est que certaines opérations qui ne sont pas définies au niveau des bits pour les types signés le sont pour les types non signés. Les types non signés n'ont pas de bit de signe, de sorte que le décalage et le masquage par le bit de signe ne posent pas de problème. Les types non signés sont utiles pour les masques de bits et pour le code qui met en œuvre une arithmétique précise indépendamment de la plate-forme. Les opérations non signées simuleront la sémantique du complément à deux, même sur une machine qui n'est pas du type complément à deux. L'écriture d'une bibliothèque multiprécision (bignum) nécessite pratiquement l'utilisation de tableaux de types non signés pour la représentation, plutôt que de types signés.

Les types non signés conviennent également aux situations dans lesquelles les nombres se comportent comme des identificateurs et non comme des types arithmétiques. Par exemple, une adresse IPv4 peut être représentée par un type non signé de 32 bits. On n'additionne pas des adresses IPv4.

2voto

Luchian Grigore Points 136646

int est préféré car il est le plus couramment utilisé. unsigned est généralement associé à des opérations sur les bits. Chaque fois que je vois un unsigned Je suppose qu'il est utilisé pour la manipulation des bits.

Si vous avez besoin d'une plus grande plage, utilisez un entier de 64 bits.

Si vous itérez sur des éléments à l'aide d'index, les types ont généralement des size_type et vous ne devriez pas vous soucier de savoir s'il est signé ou non signé.

La vitesse n'est pas un problème.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X