2011-09-25 28 views
7

Estaba leyendo en el estándar C99 sobre las conversiones aritméticas habituales.C conversiones aritméticas habituales

Si ambos operandos tienen el mismo tipo, entonces no es necesario realizar más conversiones para .

lo contrario, si los dos operandos han firmado tipos de enteros o ambos tienen tipos de enteros sin signo, el operando con el tipo de menor número entero rango de conversión se convierte en el tipo del operando con mayor rango.

De lo contrario, si el operando que tiene tipo entero sin signo tiene rango mayor o igual que el rango del tipo del otro operando, entonces el operando con el tipo entero con signo se convierte en el tipo de la operando con tipo entero sin signo.

De lo contrario, si el tipo del operando con el tipo entero con signo puede representar todos los valores del tipo del operando con unsigned tipo entero, entonces el operando con el tipo entero sin signo se convierte al tipo de el operando con tipo entero con signo.

De lo contrario, ambos operandos se convierten al entero sin signo tipo correspondiente al tipo del operando con tipo entero con signo.

Digamos que tengo el siguiente código:

#include <stdio.h> 

int main() 
{ 
    unsigned int a = 10; 
    signed int b = -5; 

    printf("%d\n", a + b); /* 5 */ 
    printf("%u\n", a + b); /* 5 */ 
    return 0; 
} 

pensé que se aplica el párrafo en negrita (ya unsigned int y signed int tienen el mismo rango ¿Por qué no es B convertido a unsigned O tal vez.? se convierte en sin firmar, pero hay algo que no entiendo?

Gracias por su tiempo :-)

+0

¿Qué te hace pensar que 'b' no se convierte en' unsigned'? –

+0

@Charles Bailey Supongo que esperaba tontamente resultados diferentes para los printfs: -? – user963368

+0

+5 es +5, independientemente de si el int está firmado o no. –

Respuesta

5

0x0000000a más 0xfffffffb siempre será 0x00000005 independientemente de si está tratando con tipos firmados o sin firmar, siempre que solo se utilicen 32 bits.

+0

¿Quiere decir que se desborda y se reduce el módulo '2^32'? – user963368

+2

Se desborda, y el resultado es que parece que se ha aplicado el módulo. –

+0

En realidad para el desbordamiento estándar de C con enteros ** signed ** no se define el comportamiento (incluso si de hecho hoy en día, esperaría que cada hardware utilice representación de 2 complementos para enteros). – 6502

0

se convirtió al unsigned, la aritmética sin signo da el resultado que ves. El resultado de aritmética sin signo es equivalente a hacer aritmética con signo con complemento de dos y sin excepción fuera de rango.

+0

¿Estás hablando de desbordamiento sin firmar? – user963368

+1

'unsigned' no se desborda (en términos del estándar) sino que simplemente se envuelve. Esto está bien definido en el estándar. –

5

Indeed bes convertido a unsigned. Sin embargo, lo que ha observado es que b convertidos a firmar y luego se añadió a 10 da como valor de 5.

En 32 bits x86 esto es lo que sucede

  1. b, convertida a firmar, se convierte en 4294967291 (es decir,2**32 - 5)
  2. la adición de 10 se convierte en 5 a causa de wrap-around en 2**32 (2**32 - 5 + 10 = 2**32 + 5 = 5)
+0

Gracias por su respuesta. Tristemente no tengo suficientes representantes para +1. – user963368

3

Repetición de la porción relevante del código de la pregunta:

unsigned int a = 10; 
signed int b = -5; 

printf("%d\n", a + b); /* 5 */ 
printf("%u\n", a + b); /* 5 */ 

En a + b, b se convierte en unsigned int, (produciendo UINT_MAX + 1 - 5 por la regla para la conversión de unsigned-to-signed). El resultado de sumar 10 a este valor es 5, según las reglas de la aritmética sin signo, y su tipo no tiene signo int. En la mayoría de los casos, el tipo de una expresión C es independiente del contexto en el que aparece. (Tenga en cuenta que nada de esto depende de la representación, la conversión y la aritmética se definen exclusivamente en términos de valores numéricos.)

Para el segundo printf llamada, el resultado es sencillo: "%u" espera un argumento de tipo unsigned int, y usted' ve dado uno. Imprime "5\n".

La primera printf es un poco más complicada. "%d" espera un argumento de tipo int, pero le está dando un argumento de tipo unsigned int. En la mayoría de los casos, un desajuste de tipo como este produce un comportamiento indefinido, pero hay una regla de caso especial de que los tipos firmados y no firmados correspondientes son intercambiables como argumentos de función, siempre que el valor sea representable en ambos tipos (como lo es aquí) . Entonces, el primer printf también imprime "5\n".

Nuevamente, todo este comportamiento se define en términos de valores, no representaciones (excepto el requisito de que un valor dado tenga la misma representación en los tipos firmados y no firmados correspondientes). Obtendrá el mismo resultado en un sistema donde firm firm int y unsigned int son ambos 37 bits, signed int tiene 7 bits de relleno, unsigned int tiene 11 bits de relleno, y firm int utiliza un complemento 1s o signo-y-magnitud representación. (No existe tal sistema en la vida real, hasta donde yo sé).

Cuestiones relacionadas