Est-il important de déclarer une variable comme non signée si l'on sait qu'elle ne doit jamais être négative ? Cela permet-il d'éviter que des nombres autres que négatifs soient introduits dans une fonction qui ne devrait pas en avoir ?
Réponses
Trop de publicités?Est-il important de déclarer une variable comme non signée si l'on sait qu'elle ne doit jamais être négative ?
Ce n'est certainement pas important. Certaines personnes (Stroustrup et Scott Meyers, voir "Unsigned vs signed - Is Bjarne mistaken ?" ) rejettent l'idée qu'une variable doit être non signée simplement parce qu'elle représente une quantité non signée. Si l'intérêt d'utiliser unsigned
serait d'indiquer qu'une variable ne peut stocker que des valeurs non négatives, vous devez le vérifier d'une manière ou d'une autre. Sinon, tout ce que vous obtenez, c'est
- Un type qui cache silencieusement les erreurs parce qu'il ne permet pas aux valeurs négatives d'être exposées.
- Double de la plage positive du type signé correspondant
- Sémantique définie pour les débordements, les décalages de bits, etc.
Cela n'empêche certainement pas les gens de fournir des valeurs négatives à votre fonction, et le compilateur ne sera pas en mesure de vous avertir de tels cas (pensez à une valeur d'entrée négative basée sur la durée d'exécution qui est passée). Pourquoi ne pas affirmer dans la fonction à la place ?
assert((idx >= 0) && "Index must be greater/equal than 0!");
Le type non signé présente également de nombreux pièges. Il faut être prudent lorsqu'on l'utilise dans des calculs qui peuvent être temporairement inférieurs à zéro (boucle de comptage descendant, par exemple) et surtout dans les promotions automatiques qui se produisent dans les langages C et C++ entre les valeurs non signées et signées.
// assume idx is unsigned. What if idx is 0 !?
if(idx - 1 > 3) /* do something */;
Cela a de la valeur pour la même raison que " const
La "justesse" a de la valeur. Si vous savez qu'une valeur particulière ne doit pas changer, déclarez-la const
et laissez le compilateur vous aider. Si vous savez qu'une variable doit toujours être non négative, déclarez-la comme suit unsigned
et le compilateur vous aidera à détecter les incohérences.
(Cela, et vous pouvez exprimer des nombres deux fois plus grands si vous utilisez unsigned int
plutôt que int
dans ce contexte).
En utilisant des valeurs non signées lorsque des valeurs signées ne sont pas nécessaires, vous vous assurez que le type de données ne représente pas de valeurs inférieures à la limite inférieure souhaitée et vous augmentez la limite supérieure maximale. Toutes les combinaisons de bits qui seraient autrement utilisées pour représenter des nombres négatifs sont utilisées pour représenter un ensemble plus large de nombres positifs.
Il n'empêchera pas les nombres négatifs d'être introduits dans une fonction, mais les interprétera comme de grands nombres positifs. Cela peut être modérément utile si vous connaissez une limite supérieure pour le contrôle des erreurs, mais vous devez effectuer le contrôle des erreurs vous-même. Certains compilateurs émettront des avertissements, mais si vous utilisez beaucoup de types non signés, il se peut qu'il y ait trop d'avertissements pour que vous puissiez les traiter facilement. Ces avertissements peuvent être couverts par des casts, mais c'est pire que de s'en tenir uniquement aux types signés.
Je n'utiliserais pas un type non signé si je savais que la variable ne devait pas être négative, mais plutôt si elle ne pouvait pas l'être. size_t
est un type non signé, par exemple, car un type de données ne peut tout simplement pas avoir une taille négative. Si une valeur peut être négative mais ne doit pas l'être, il est plus facile de l'exprimer en la considérant comme un type signé et en utilisant quelque chose comme i < 0
o i >= 0
(ces conditions se traduisent par false
y true
respectivement si i
est un type non signé, quelle que soit sa valeur).
Si vous êtes soucieux de respecter strictement la norme, il peut être utile de savoir que les débordements dans l'arithmétique non signée sont entièrement définis, alors que dans l'arithmétique signée, il s'agit d'un comportement non défini.