92 votes

Signé/non signé comparaisons

J'essaie de comprendre pourquoi le code suivant ne pas émettre un avertissement à l'endroit indiqué.

//from limits.h
#define UINT_MAX 0xffffffff /* maximum unsigned int value */
#define INT_MAX  2147483647 /* maximum (signed) int value */
            /* = 0x7fffffff */

int a = INT_MAX;
//_int64 a = INT_MAX; // makes all warnings go away
unsigned int b = UINT_MAX;
bool c = false;

if(a < b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a > b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a <= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a >= b) // warning C4018: '<' : signed/unsigned mismatch
    c = true;
if(a == b) // no warning <--- warning expected here
    c = true;
if(((unsigned int)a) == b) // no warning (as expected)
    c = true;
if(a == ((int)b)) // no warning (as expected)
    c = true;

Je pensais que c'était à faire avec l'arrière-plan de la promotion, mais les deux derniers semblent dire le contraire.

À mon avis, la première == comparaison est tout autant un signed/unsigned incompatibilité que les autres?

105voto

Erik Points 38942

Lorsque l'on compare signé avec non signé, le compilateur convertit la valeur signée non signé. Pour l'égalité, ce n'est pas grave, -1 == (unsigned) -1. Pour les autres comparaisons, il importe, par exemple, ce qui suit est vrai: -1 > 2U.

EDIT: Références:

5/9: (Expressions)

De nombreux opérateurs binaires qui attendent les opérandes de l'arithmétique ou de l'énumération type de provoquer des conversions et le rendement les types de résultats de manière similaire. L' le but est de produire un type commun, ce qui est aussi le type du résultat. Ce modèle est appelé l'habitude l'arithmétique des conversions, qui sont définis comme suit:

  • Si l'opérande est de type long double, la d'autres sont convertis à long double.

  • Sinon, si l'un des deux opérandes est double, l'autre doit être converti en double.

  • Sinon, si l'un des deux opérandes est float, l'autre doit être converti en float.

  • Sinon, l'intégrale des promotions (4.5) doit être effectuée sur les deux opérandes.54)

  • Alors, si l'un des deux opérandes est unsigned long de l'autre doit être converti unsigned long.

  • Sinon, si l'un des opérandes est un long int et l'autre unsigned int, alors si un long int peut représenter toutes les les valeurs d'un type unsigned int, le unsigned int est converti en long int, sinon les deux opérandes doit être converti en unsigned long int.

  • Sinon, si l'un des deux opérandes est long, l'autre est converti à long.

  • Sinon, si l'un des deux opérandes n'est pas signée, l'autre doit être convertis non signé.

4.7/2: (Intégrale des conversions)

Si le type de destination n'est pas signé, la valeur obtenue est le moins entier non signé conforme à la source entier (modulo 2n où n est le nombre de bits utilisés pour représenter le type non signé). [Note: Dans un à deux, en complément de la représentation, ce la conversion est conceptuel et il est pas de changement dans la séquence de bits (si il y est pas de troncature). ]

EDIT2: MSVC des niveaux d'alerte

Ce qui est averti à ce sujet sur les différents niveaux d'alerte de MSVC est, bien sûr, les choix effectués par les développeurs. Comme je le vois, leurs choix en matière de signed/unsigned l'égalité vs plus de/moins de comparaisons sens, c'est totalement subjectif, bien sûr:

-1 == -1 signifie la même chose que -1 == (unsigned) -1 - je trouve que d'une interface intuitive de résultat.

-1 < 2 n'a pas la même signification que -1 < (unsigned) 2 - Ce qui est moins intuitif au premier coup d'œil, et de l'OMI qui mérite un "plus tôt" alerte.

34voto

Nawaz Points 148870

Pourquoi signed/unsigned avertissements sont importants et que les programmeurs doivent prêter attention à eux, est démontré par l'exemple suivant.

Suppose que la sortie de ce code?

#include <iostream>

int main() {
        int i = -1;
        unsigned int j = 1;
        if ( i < j ) 
            std::cout << " i is less than j";
        else
            std::cout << " i is greater than j";

        return 0;
}

Sortie:

i is greater than j

Surpris? Démo en ligne : http://www.ideone.com/5iCxY

La ligne de fond: à titre de comparaison, si l'un des opérandes est - unsigned, puis de l'autre opérande est implicitement converti en unsigned si son type est signé!

5voto

Yochai Timmer Points 19802

L'opérateur == ne fonctionne tout simplement une comparaison bit à bit (par simple division pour voir si il est à 0).

Le plus petit/plus grand que les comparaisons se basent beaucoup plus sur le signe du nombre.

4 bits Exemple:

1111 = 15 ? ou -1 ?

donc, si vous avez 1111 < 0001 ... c'est ambigu...

mais si vous avez 1111 == 1111 ... C'est la même chose même si vous n'avez pas dire qu'il soit.

2voto

Hossein Points 2286

Dans un système qui représente les valeurs à l'aide de 2-complément (la plupart des processeurs modernes) ils sont égaux, même dans leur forme binaire. C'est peut-être pourquoi le compilateur n'a pas à se plaindre a == b.

Et pour moi, c'est étrange compilateur de ne pas vous mettre en garde sur a == ((int)b). Je pense qu'il devrait vous donner un entier troncature d'avertissement ou de quelque chose.

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