11 votes

L'importance de déclarer une variable comme non signée

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 ?

21voto

AndreyT Points 139512

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.

6voto

Steve Townsend Points 36948

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.

4voto

miked Points 1993

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.

4voto

Jeremy Friesner Points 16684

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]);

4voto

Evan Teran Points 42370

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 .

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