sin firmar largo 0 <-1?

¡No consigo este!

#include  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 resulta en:

  s1 < s2-1 

O bien ambos deberían fallar o ambos no. Intenté esto con gcc 4 y 4.2

El lenguaje C realiza las “conversiones aritméticas habituales” para muchos operadores; las conversiones se describen en 6.3.1.8 del estándar C99. Para los 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 / booleanos, caracteres y enteros), que dice entre otras cosas:

Si un int puede representar todos los valores del tipo original, el valor se convierte en un int; de lo contrario, se convierte en un int sin signo. Estos se llaman las promociones enteras. Todos los otros tipos no se modifican por las promociones enteras.

Las promociones se aplican solo a objetos o expresiones con un tipo entero con un rango menor que int y unsigned int (o bitfields).

Así que en tu expresión:

 t1 < t2-1 

a pesar de que las variables son unsigned short , se promueven 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 tipos int , y no se produce subdesbordamiento: la parte t2-1 de la expresión termina como 1 negativa.

En la expresión:

 s1 < s2-1 

los tipos unsigned long no se promueven, porque tienen un 'rango' más alto que int / unsigned int , por lo que la expresión se evalúa utilizando aritmética sin signo (con el subdesbordamiento de la resta), y la subexpresión s2-1 evalúa a un nivel muy alto Gran número, no negativo 1.

Como lo indica litb en un comentario, si la plataforma se hubiera implementado como un tipo de 16 bits (lo que está permitido, por ejemplo, MS-DOS), la promoción de unsigned short sería a unsigned int lugar de int , ya que un int no lo haría t poder representar todos los valores de unsigned short unsigned short (el unsigned short debe tener al menos 16 bits). En ese caso, ambas afirmaciones se evaluarían como verdaderas.

No estoy seguro, pero sospecho que la expresión t2-1 se amplía 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.

Las coerciones, como está descubriendo, no siempre son obvias, siempre que se opera entre diferentes tipos. t2 es u16, 1 es int (probablemente de 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, dado que s2 y 1 son ambos de 32 bits (aunque con una firma diferente), la coerción general es demasiado larga. Por lo tanto, los tamaños de los tipos involucrados ayudan a determinar la firmeza de la coerción general.

Sugiero evitar las operaciones de firma mixta (¡e idealmente también de tamaño mixto!) (Mediante el lanzamiento o la notación literal especial para literales como 1 que, de lo contrario, tendrán un tipo int y harán su vida potencialmente complicada y su código potencialmente inportable ;-).

-1 se representa como todos los 1s. Por lo tanto, cuando se interpreta como no firmado, su valor es 2 ^ 32-1, que es claramente mayor que 0. Supongo que la primera comparación se está expandiendo para realizar una aritmética con signo de 32 bits (tal vez debido a que el “1” es un firmado int).

Tenga en cuenta que lo siguiente LLEGARÁ al printf, porque la comparación ahora se realiza en un espacio sin signo de 16 bits de nuevo:

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