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?Déclarer des variables pour des valeurs sémantiquement non négatives comme unsigned
est un bon style et une bonne pratique de programmation.
Cependant, gardez à l'esprit que cela ne vous empêche pas de faire des erreurs. Il est parfaitement légal d'attribuer des valeurs négatives à des entiers non signés, la valeur étant implicitement convertie en forme non signée conformément aux règles de l'arithmétique non signée. Certains compilateurs peuvent émettre des avertissements dans de tels cas, d'autres le font discrètement.
Il convient également de noter que le travail avec des entiers non signés nécessite la connaissance de certaines techniques spécifiques aux entiers non signés. Par exemple, un exemple "classique" qui est souvent mentionné en relation avec cette question est l'itération à rebours
for (int i = 99; i >= 0; --i) {
/* whatever */
}
Le cycle ci-dessus semble naturel avec la signature i
mais il ne peut pas être directement converti en forme non signée, ce qui signifie que
for (unsigned i = 99; i >= 0; --i) {
/* whatever */
}
ne fait pas vraiment ce qu'il est censé faire (il s'agit en fait d'un cycle sans fin). La technique appropriée dans ce cas est soit
for (unsigned i = 100; i > 0; ) {
--i;
/* whatever */
}
o
for (unsigned i = 100; i-- > 0; ) {
/* whatever */
}
Ceci est souvent utilisé comme argument contre les types non signés, c'est-à-dire que les versions non signées du cycle ci-dessus semblent "peu naturelles" et "illisibles". En réalité, le problème auquel nous sommes confrontés ici est le problème générique du travail près de l'extrémité gauche d'un intervalle fermé-ouvert. Ce problème se manifeste de différentes manières en C et C++ (comme l'itération à rebours sur un tableau en utilisant la technique du "pointeur glissant" ou l'itération à rebours sur un conteneur standard à l'aide d'un itérateur). En d'autres termes, même si les cycles non signés ci-dessus vous paraissent inélégants, il n'y a aucun moyen de les éviter complètement, même si vous n'utilisez jamais de types entiers non signés. Il est donc préférable d'apprendre ces techniques et de les inclure dans votre ensemble d'idiomes établis.
Cela n'empêche pas les gens d'utiliser votre interface à mauvais escient, mais ils devraient au moins recevoir un avertissement à moins qu'ils n'ajoutent un cast de style C ou un static_cast
pour le faire disparaître (auquel cas vous ne pouvez plus l'aider).
Oui, cela a de la valeur car cela exprime correctement la sémantique que vous souhaitez.
Il fait deux choses :
1) Il vous permet de doubler l'étendue de vos valeurs non signées. Lorsqu'il est "signé", le bit le plus élevé est utilisé comme bit de signe (1 signifie négatif, 0 positif) ; lorsqu'il est "non signé", vous pouvez utiliser ce bit pour les données. Par exemple, un char
passe de -128 à 127, un type de unsigned char
va de 0 à 255
2) Il affecte la manière dont le >>
agit, en particulier lors du décalage vers la droite de valeurs négatives.
Un petit avantage est qu'il réduit la quantité de tests de vérification des limites des tableaux qui pourraient être nécessaires... par exemple, au lieu d'avoir à écrire :
int idx = [...];
if ((idx >= 0)&&(idx < arrayLength)) printf("array value is %i\n", array[idx]);
vous pouvez simplement écrire :
unsigned int idx = [...];
if (idx < arrayLength) printf("array value is %i\n", array[idx]);
Les autres réponses sont bonnes, mais elles peuvent parfois prêter à confusion. C'est, je crois, la raison pour laquelle certaines langues ont choisi de ne pas avoir de unsigned
les types de nombres entiers.
Par exemple, supposons que vous disposiez d'une structure ressemblant à celle-ci pour représenter un objet d'écran :
struct T {
int x;
int y;
unsigned int width;
unsigned int height;
};
L'idée est qu'il est impossible d'avoir une largeur négative. Quel type de données utilisez-vous pour stocker le bord droit du rectangle ?
int right = r.x + r.width; // causes a warning on some compilers with certain flags
et il est certain qu'il ne vous protège toujours pas contre les débordements d'entiers. Ainsi, les dans ce scénario, même si width
y height
ne peuvent pas être conceptuellement négatifs, il n'y a pas de gain réel à les rendre négatifs. unsigned
à l'exception de quelques casts nécessaires pour se débarrasser des avertissements concernant le mélange de types signés et non signés. En fin de compte, au moins pour des cas comme celui-ci, il est préférable de les rendre tous int
Après tout, il y a de fortes chances que vous ne disposiez pas d'une fenêtre suffisamment large pour que vous puissiez vous en servir comme d'un outil de travail. besoin Il s'agit d'être unsigned
.
- Réponses précédentes
- Plus de réponses