2009-09-12 10 views
8

¡No obtengo este!unsigned long 0 <-1?

#include <stdio.h> 

int main() 
{ 
    unsigned short t1 = 0, t2 = 0; 

    if(t1 < t2-1) 
     printf(" t1 < t2-1\n"); 

    unsigned long s1 = 0, s2 = 0; 

    if(s1 < s2-1) 
     printf(" s1 < s2-1\n"); 
} 

esto se traduce en:

s1 < s2-1 

Cualquiera de ambos deben fallar o no tanto. Intenté esto con gcc 4 & 4.2

+0

~ nairboon: Espero que no te importe la edición. El código con el que reemplacé el suyo es funcionalmente el mismo, pero se puede copiar/pegar en un editor y compilar sin cambios. –

+1

Tenga en cuenta que no se garantiza que este resultado sea el resultado. En las máquinas donde int almacena el mismo rango de valores que corto (creo que máquinas de 16 bits), verá salida para ambos ifs, porque la promoción se convertirá a unsigned int entonces, en lugar de a int. –

Respuesta

12

El lenguaje C realiza las "conversiones aritméticas habituales" para muchos operadores - la las conversiones se describen en 6.3.1.8 del estándar C99. Para operandos integrales, se realizan las primeras promociones, y esto es lo que está causando su problema. Las promociones se describen en 6.3.1.1 (operandos aritméticos/booleanas, personajes y enteros), que dice entre otras cosas:

Si un int puede representar todos los valores del tipo original, el valor se convierte en una En t; de lo contrario, se convierte a unsigned int. Estas se llaman promociones enteras. Todos los otros tipos no se modifican por las promociones enteras.

Las promociones sólo se aplican a los objetos o expresiones con un tipo entero con un rango de menos de int y unsigned int (o campos de bits).

Así que en su exression:

t1 < t2-1 

a pesar de que las variables son unsigned short son promovidos a int, ya que en su plataforma int puede representar todos los valores de unsigned short. Por lo tanto, la expresión se evalúa utilizando los tipos int, y no se produce subdesbordamiento - la parte t2-1 de la expresión termina como negativa 1.

En la expresión:

s1 < s2-1 

los tipos unsigned long no se promueven, porque tienen un mayor 'ranking' de int/unsigned int, por lo que la expresión se evalúa usando aritmética sin signo (con la corriente de fondo de la resta), y la s2-1 sub-expresión se evalúa como un número muy grande, no es negativo 1.

como litb se indica en un comentario, si la plataforma había int implementado como un tipo de 16 bits (lo cual está permitido - MS-DOS para ejemplo), el profesional el movimiento de unsigned short sería unsigned int en lugar de int, ya que un int no podría representar todos los valores de unsigned short (unsigned short debe ser de al menos 16 bits). En ese caso, ambas declaraciones if se evaluarían como verdaderas.

13

No estoy seguro, pero sospecho que la expresión t2-1 se amplió automáticamente en un valor int. No tengo el estándar c aquí cuáles son las reglas de conversión exactas, pero creo que los tipos más pequeños que int se amplían automáticamente.

+3

+1, en una expresión aritmética, los objetos de los tipos (con y sin firma) short y (signed/unsigned /) char son * promote * to int. – avakar

+1

Esta respuesta sería mucho mejor si dijera que ** 't2' ** se convierte en int, no **' t2-1' ** (para que quede claro que la conversión ocurre * antes * de la resta). –

3

Las coerciones C, como está descubriendo, no siempre son obvias, cada vez que opera entre diferentes tipos. t2 es u16, 1 es int (presumiblemente 32 bits), por lo que t2-1 es exactamente una "operación entre diferentes tipos" y da como resultado una coerción general a int (ya que es "más larga" que u16 ...). Más tarde, como s2 y 1 son ambos de 32 bits (aunque con signatura diferente), la coerción general es unsigned long. Entonces, los tamaños de los tipos involucrados ayudan a determinar la firma de la coerción general.

me sugieren evitar mixta de signo operaciones (a través de la fundición o la notación literal especial para literales como 1 que de lo contrario tendrán int tipo y hacer su vida potencialmente complicado y su código potencialmente no portables (e idealmente también mixta de tamaño!); -).

0

-1 se representa como todos 1s. Por lo tanto, cuando se interpreta como sin signo, su valor es 2^32-1, que es claramente mayor que 0. Supongo que la primera comparación se está ampliando para realizar operaciones aritméticas de 32 bits (quizás debido a que el "1" es un firmado int).

cuenta que la siguiente va a llegar al printf, porque la comparación se hace ahora en 16 bits espacio sin firmar de nuevo:

u32 temp = t2 - 1; 
if(t1 < temp) 
    printf(" t1 < t2-1\n"); 
+4

El literal 1 (de tipo 'int') se convierte en' unsigned long' antes de la resta. Como la aritmética en los tipos sin signo siempre se realiza con el módulo '2^k', para el tipo específico' k', el resultado es '2^k-1'. La representación de -1 no está involucrada (y no es necesario que sean todas en algunas arquitecturas). – avakar

+0

La representación de -1 está involucrada en la explicación de la segunda parte: por qué 0 <-1 en longitudes sin firmar. – Yuliy

+0

No, no lo es. Como dice avakar, '-N' -> unsigned es una operación puramente matemática, que simplemente calcula' UINT_MAX + 1 - N'. No se confía en ninguna representación en ningún lado. –

Cuestiones relacionadas