web-dev-qa-db-fra.com

C/C++ utilisation de int ou unsigned int

Dans beaucoup d'exemples de code, code source, bibliothèques, etc., je vois l'utilisation de int lorsque, autant que je sache, un unsigned int aurait beaucoup plus de sens.

Un endroit que je vois souvent est dans les boucles for. Voir ci-dessous exemple:

for(int i = 0; i < length; i++)
{
    // Do Stuff
}

Pourquoi diable utiliseriez-vous une int plutôt qu'un unsigned int? Est-ce juste de la paresse - les gens ne peuvent pas s'embêter à taper unsigned?

24
developerbmw

Utiliser unsigned peut introduire des erreurs de programmation difficiles à repérer, et il est généralement préférable d'utiliser int signé pour les éviter. Un exemple serait lorsque vous décidez d’itérer une itération en arrière plutôt qu’en suivant et écrivez ceci:

for (unsigned i = 5; i >= 0; i--) {
    printf("%d\n", i);
}

Une autre serait si vous faites des calculs dans la boucle:

for (unsigned i = 0; i < 10; i++) {
    for (unsigned j = 0; j < 10; j++) {
        if (i - j >= 4) printf("%d %d\n", i, j);
    }
}

Utiliser unsigned introduit le potentiel de ce type de bugs, et il n’ya vraiment aucun avantage.

21
Paul Hankin

C'est généralement la paresse ou le manque de compréhension.

J'utilise toujours unsigned int lorsque la valeur ne doit pas être négative. Cela sert également l’objet de documentation de spécifier quelles sont les valeurs correctes.

IMHO, l'affirmation qu'il est plus sûr d'utiliser "int" que "unsigned int" est tout simplement fausse et une mauvaise pratique de programmation.

Si vous avez utilisé Ada ou Pascal, vous seriez habitué à utiliser la pratique encore plus sûre de spécifier des plages spécifiques pour les valeurs (par exemple, un entier ne pouvant être que 1, 2, 3, 4, 5).

7
user3344003

J'ai choisi d'être aussi explicite que possible lors de la programmation. En d’autres termes, si j’ai l’intention d’utiliser une variable dont la valeur est toujours positive, alors unsigned est utilisé. Beaucoup ici parlent de "bugs difficiles à repérer" mais peu d’exemples. Prenez l'exemple suivant pour l'utilisation de unsigned, contrairement à la plupart des publications ici:

enum num_things {
    THINGA = 0,
    THINGB,
    THINGC,
    NUM_THINGS
};

int unsafe_function(int thing_ID){
    if(thing_ID >= NUM_THINGS)
        return -1;

    ...
}

int safe_function(unsigned int thing_ID){
    if(thing_ID >= NUM_THINGS)
        return -1;

    ...
}

int other_safe_function(int thing_ID){
    if((thing_ID >=0 ) && (thing_ID >= NUM_THINGS))
        return -1;

    ...
}

/* Error not caught */
unsafe_function(-1);

/* Error is caught */
safe_function((unsigned int)-1);

Dans l'exemple ci-dessus, que se passe-t-il si une valeur négative est passée en tant que thing_ID? Dans le premier cas, vous constaterez que la valeur négative n'est pas supérieure à supérieure ou égale àNUM_THINGS et que la fonction continue de s'exécuter.

Dans le second cas, vous intercepterez cela au moment de l'exécution car la signature de thing_ID oblige la condition conditionnelle à exécuter une comparaison non signée .

Bien sûr, vous pourriez faire quelque chose comme other_safe_function, mais cela semble plutôt un kludge d'utiliser des entiers signés plutôt que d'être plus explicite et d'utiliser unsigned pour commencer.

3
sherrellbc

Si length est également int, vous devez utiliser le même type entier, sinon des choses étranges se produisent lorsque vous mélangez des types signés et non signés dans une instruction de comparaison. La plupart des compilateurs vous avertiront.

Vous pouvez ensuite demander pourquoi length devrait être signé? Eh bien, c'est probablement historique.

En outre, si vous décidez d'inverser la boucle, c'est-à-dire

for(int i=length-1;i>=0 ;i--)
{
   // do stuff
}

la logique casse si vous utilisez des ints non signés.

3
Mark Lakata

Je pense que la raison la plus importante est que si vous choisissez unsigned int, vous pouvez obtenir des erreurs de logique. En fait, vous n'avez souvent pas besoin de la plage unsigned int; utiliser int est plus sûr.

2
Khoi Pham

ce petit code est lié à une casse, si vous appelez un élément vectoriel alors le prototype est int mais il y a beaucoup de manières modernes de le faire en c ++, par exemple. for (const auto & v: vec) {} ou itérateurs, dans certains calculs s'il n'y a pas de soustraction/d'atteinte d'un nombre négatif, vous pouvez et devriez utiliser unsigned (explique mieux la plage de valeurs attendue), parfois autant d'exemples postés que vous montre need int mais la vérité est que tout est à propos de notre cas et de notre situation, aucune règle stricte ne s'applique à tous les cas et il serait un peu stupide de forcer un joueur de plus ...

0
LiorA