2010-11-17 21 views
8

He buscado en este sitio una respuesta y he encontrado muchas respuestas a la comparación sin firma/firmada, pero este problema es que solo se comparan los parámetros sin firmar, pero aún así funciona de manera divertida.unsigned se convierte en firmado en las comparaciones if-statement?

El problema con el siguiente código es que el primer if -statment no ocurre ("hola") donde lo hace el segundo ("mundo"). Esto lo he interpretado como el cálculo que se realiza dentro del if -statment genera un número negativo pero el mismo cálculo hecho con el resultado guardado en una variable no lo hace (aunque el resultado se guarda en una variable con signo).

El compilador utilizado es gcc 4.4.

unsigned short u16_varHigh; 
unsigned short u16_varLow; 
unsigned short u16_Res1; 
signed short s16_Res1; 

u16_varHigh = 0xFFFF; 
u16_varLow = 10; 

u16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected 
s16_Res1 = u16_varLow - u16_varHigh; // response is 11 as expected 

// Does not enter 
if((u16_varLow - u16_varHigh) > (unsigned short)5) 
{ 
printf("hello"); 
} 

// Does enter 
if((unsigned short)(u16_varLow - u16_varHigh) > 5) 
{ 
printf("world"); 
} 

Puede alguien explicar esto para mí y tal vez llegar a una solución para una solución de manera que la primera if -statement funciona tan bien?

+0

posible duplicado de (http [Pregunta sobre reglas de la promoción integral C.]: // stackoverflow .com/questions/2280663/question-about-c-integral-promotion-rules) – unwind

+3

No estoy de acuerdo. En un tema similar, pero no duplicado. – Kos

Respuesta

4

En la expresión:

if((u16_varLow - u16_varHigh) > (unsigned short)5) 

(u16_varLow - u16_varHigh) será promovido a una int y evaluar a -65525. La solución para su problema es convertir a un tipo sin firmar, como lo hace en el código "Does enter".

La razón s16_Res1 = u16_varLow - u16_varHigh; produce 11 es que el resultado de la resta, -65525, no cabe en un corto.

+0

En realidad es 'u16_varLow' y' u16_varHigh' que se promocionan individualmente a 'int', antes de la resta. – caf

+0

¿Se hacen dos moldes individuales? No se ingresará la siguiente instrucción if: u16_varHigh = 0xff00;
if (u16_varHigh <-5) ... La decisión de firmarlo se debe a la substracción. Entonces, comparar un unsigned (con alto bit set) se considerará unsigned, pero compare la diferencia entre 2 unsigned y se considera firmado. Se siente mal de alguna manera ... – Wilmer

+0

También vale la pena señalar que el '(short sin signo)' no tiene ningún efecto (en una máquina de 32 bits). '(unsigned short) 5' se promueve a' int' antes de ser considerado como entrada a la comparación, si todos los valores de 'unsigned short' encajan en' int'. Si hicieras esto en un procesador en el cual short e int tuvieran el mismo ancho, '(unsigned short) 5' pasaría a' unsigned', al igual que lhs, y la condición sería verdadera. – greggo

1

El primero, if((u16_varLow - u16_varHigh) > (unsigned short)5) nunca pasará, ya que (u16_varLow - u16_varHigh) devuelve un número negativo, porque se trata como un número entero. El segundo arroja el mismo número negativo, a corto sin firmar, por eso pasa.

Nota - usted sabe que todo esto depende de la plataforma, ¿verdad? El tamaño de short, int, etc. depende de la plataforma de hormigón.

+0

@Nota: estoy al tanto de esto, pero de todas maneras gracias (porque de lo contrario no me había dado cuenta de esto, me habrías ahorrado mucho trabajo) – Wilmer

2

En las otras respuestas que hemos visto que

u16_varLow - u16_varHigh 

para usted (con 16 bits short y 32 bits int) es equivalente a

(int)u16_varLow - (int)u16_varHigh 

y por lo tanto su resultado es el valor int-65525 . Por lo tanto la asignación

s16_Res1 = u16_varLow - u16_varHigh; 

es equivalente a

s16_Res1 = -65525; 

que en su caso de 16 bits short produce "comportamiento indefinido". Simplemente tiene la mala suerte de que su compilador decida asignar 11, en su lugar. (Mala suerte, porque creo que es mejor fallar temprano.)

En contraste con esto

u16_Res1 = -65525; 

es una asignación válida desde u16_Res1 es de un tipo sin signo y la aritmética de los tipos sin signo es de módulo la potencia adecuada de dos.

2

En las "conversiones aritméticas habituales", los tipos más pequeños que int se promueven a int o unsigned int antes de que se usen en la mayoría de las expresiones. La regla es que si int puede representar todos los valores del tipo más pequeño, entonces se promueve a int; de lo contrario, se promociona al unsigned int. Esto a menudo se considera algo así como una verruga, porque en muchos casos provoca que los valores unsigned char y unsigned short se promuevan a int.

Esto es exactamente lo que se está viendo - u16_varLow y u16_varHigh y (unsigned short)5 todos son promovidos a int antes de la resta y la comparación, que luego suceda usando int. Si desea estar seguro de que una expresión aritmética utilizará sin firmar, debe hacerlo en unsigned int, no unsigned short:

if(((unsigned)u16_varLow - (unsigned)u16_varHigh) > 5U) 
Cuestiones relacionadas