2010-11-22 13 views
6

Cuando compilo el siguiente código, mi compilador se queja de que la siguiente línea siempre es verdadera. Creo que puede tener una comprensión defectuosa del operador != ...¿Por qué esta condición es siempre cierta? (pktNum! = invPktNum)

if (pktNum != ~invPktNum) { 
    return 1; 
} 

Estoy intentando verificar que invPktNum es de hecho la inversa de pktNum. De lo contrario, salga de inmediato; de lo contrario, proceda de la forma habitual.

He comprobado y pktNum un carácter sin signo que es 0x01 y invPktNum es un carácter sin signo que es 0xFE en el momento de la comparación.

¿Alguien me puede aclarar? ¡Gracias por adelantado!

Respuesta

10

En C, los valores en la mayoría de las expresiones que son de un tipo más estrecho que int se promueven a un tipo más amplio antes de que el cálculo tenga lugar. Si int es lo suficientemente ancho para contener todos los valores del tipo más estrecho, entonces se promueve a int; de lo contrario, se promociona al unsigned int.

En este caso, int es lo suficientemente amplia como para contener todos los valores de su unsigned char, por lo que sus valores son promovidos a int.

pktNum (y por lo tanto, el promocionado pktNum) puede tener un valor entre 0 y 255 inclusive. Este es el valor que se utilizará en el lado izquierdo del operador !=.

También puede tener un valor 0 a 255 inclusive. Este valor se promocionará a int, y luego se negará en bits. El resultado de esta negación a nivel de bits siempre será un número negativo, ya que el bit de signo será negado. Este es el valor que se usará en el lado derecho del operador !=.

Ningún número negativo puede ser igual al promocionado pktNum, por lo que la condición siempre es verdadera.

para realizar el cálculo que en realidad se quiere, lo que necesita para enmascarar los más bajos ocho bits después de la negación:

if (pktNum != (~invPktNum & 0xff)) { 
    return 1; 
} 

O, alternativamente, puede simplemente negar los bits que le interesan:

if (pktNum != (invPktNum^0xff)) { 
    return 1; 
} 
+0

Ah, esto fue todo, y aprendí algo nuevo. ¡Gracias por tu respuesta maravillosamente detallada! – Justin

+0

@ FallSe7en: Bienvenido al mundo maravillosamente confuso de la depuración de C-code. ¡Imagínese tratando de encontrar ese error sin la advertencia del compilador! –

0

Estás viendo valores de 8 bits. Apuesto a que pktNum e invPktNum son valores de 32 bits, por lo que comparas 0x000000fe con 0xfffffffe.

+0

Si estoy escribiendo código para un microcontrolador de 16 bits, ¿sería un carácter sin signo de 16 bits? Pensé que un char sin signo solo tenía 8 bits. – Justin

+0

'char' se supone que es tan ancho como' CHAR_BIT' de '' (creo) define. – dennycrane

+0

¿De qué tipo son? No estás especificando eso en tu pregunta. – EboMike

-1

Suponiendo lo siguiente:

invPktNum = ~pktNum 

entonces su comparación es equivalente a:

if (pktNum != ~(~pktNum)) { 

o

if (pktNum != pktNum) { 

que siempre es falsa. A menos que invPktNum tenga una definición diferente en su código que no se muestra.

+1

El compilador se queja de que siempre es * verdadero *. – caf

+0

¿Puede agregar las declaraciones completas de invPktNum y pktNum a la pregunta original? – uesp

0

Tal vez la prueba independiente tipo simple es:

if (0 == (pktNum & pkNum)) { 

Qué i S igual a:

if (0 == (0xfe & 0x01)) { 

probado rápidamente con http://codepad.org/nziOGYJG parece funcionar con múltiples con y sin signo tipos largos/INT.

Sin interés ¿alguien tiene algún comentario?

+1

Eso no da la misma semántica que el original (previsto); esto solo puede ser cierto si y solo si una de las entradas es 0. 'if ((pktNum^invPktNum)! = 0xff)' funciona, pero yo no pienses que es tan claro. – caf

+0

@caf Gracias por tu opinión. Estoy de acuerdo con que no está tan claro. –

Cuestiones relacionadas