2010-09-08 26 views
8
signed int x= -5; 
unsigned int y=x; 

¿cuál es el valor de y? ¿y cómo?Valores sin signo y con signo en C (¿cuál es la salida?)

+5

al realizar esta búsqueda, ¿Qué viste? –

+4

@KennyTM, no implementación definida; La conversión de un int sin signo a un int. firmado que no puede representarlo está definida por la implementación, pero al revés (signed -> unsigned) está bien definida. – bdonlan

+2

@bdonlan: 'UINT_MAX' * is * implementación definida. – kennytm

Respuesta

-1

y = 0xfffffffb que es la representación binaria de -5 (complemento de dos)

+0

Puede por favor explicarlo más ... –

+1

El resultado no depende de ninguna "representación binaria". El resultado está dictado por los requisitos del estándar de idioma. Y el estándar es bastante explícito en este caso. – AnT

+0

@AndreyT. Para ser justos, aunque no se indique de esta manera, es cierto que el complemento de 2 -> conversión sin firmar da como resultado el mismo patrón de bits (creo que el estándar de C++ menciona esto de pasada, no puedo recordar si el estándar C) La descripción de Philibert es equivalente a la definición en el estándar: puede convertir firmado -> sin signo elaborando la representación del complemento a 2 del valor con signo, y luego leerlo como un valor sin signo. Nunca dijo que así es como la implementación realmente lo hace (aunque sin duda las implementaciones de complemento 2 sí). –

16

Depende del valor máximo de la unsigned int. Típicamente, un unsigned int es de 32 bits de largo, por lo que el UINT_MAX es 2 − 1. El estándar C (§ 6.3.1.3/2) requiere un → conversión unsigned firmado ser realizado como

lo contrario, si el nuevo tipo no está firmado, el valor se convierte al agregar o restar repetidamente uno más que el valor máximo que se puede representar en el nuevo tipo hasta que el valor esté en el rango del nuevo tipo.

Por lo tanto y = x + ((2 − 1) + 1) = 2 − 5 = 4294967291.


En una plataforma 2's complement, que la mayoría de las implementaciones son hoy en día, y también es lo mismo que la representación de complemento de 2 de x.

-5 = ~ 5 + 1 = 0xFFFFFFFA + 1 = 0xfffffffb = 4294967291.

2

El valor de y es UINT_MAX - 5 + 1, es decir UINT_MAX - 4.

Al convertir un valor entero con signo a un tipo sin signo, se reduce el valor del módulo 2^N, donde N es el número de bits de formación de valor en el tipo sin signo. Esto se aplica a los valores con signo negativo y positivo.

Si va a convertir de un tipo firmado al tipo sin signo del mismo tamaño, lo anterior significa que valores con signo positivo se mantienen sin cambios (+5 se convierte a 5, por ejemplo) y los valores negativos se agregan a MAX + 1, donde MAX es el el valor máximo del tipo sin firmar (-5 se convierte a MAX + 1 - 5).

4

de la norma C99:

6.3.1.3 Firmado y enteros sin signo

  1. Cuando un valor con el tipo de número entero se convierte a otro número entero tipo distinto _Bool, si El valor puede ser representado por el nuevo tipo, no se modifica.
  2. De lo contrario, si el nuevo tipo es sin signo, el valor se convierte por añadiendo repetidamente o restando uno más que el valor máximo que puede ser representado en el nuevo tipo de hasta que el valor está en el rango del nuevo tipo . 49)

49) Las reglas describen la aritmética en el valor matemático, no el valor de un tipo de expresión dado.

Así que usted estará mirando, efectivamente, y = x + UINT_MAX + 1.

Esto simplemente significa que la representación de dos complementos se utiliza sin cambios como un entero sin signo, lo que hace que esto sea muy rápido en la mayoría de las computadoras modernas, ya que utilizan el complemento de dos para enteros con signo.

+3

Falta un elemento: UINT_MAX es 2^N-1. –

+0

No del todo correcto. La fórmula correcta es 'y = x + UINT_MAX - 1'. – AnT

+1

@AndreyT: En realidad, la fórmula correcta es 'y = x + UINT_MAX + 1'. – kennytm

1

Los valores con signo se almacenan normalmente como algo que se llama two's complement:

de dos números en complemento son una forma de codificar los números negativos en binario ordinaria, de manera que además todavía funciona. Agregar -1 + 1 debe ser igual a 0, pero la adición ordinaria da el resultado de 2 o -2 a menos que la operación tenga especial atención en el bit de signo y realice una resta en su lugar. El complemento a dos da como resultado la suma correcta sin este paso adicional.

Esto significa que la representación real de los números -5 y 4294967291 en la memoria (para una palabra de 32 bits) son idénticos, por ejemplo: 0xFFFFFFFB o 0b11111111111111111111111111111011. Así que cuando lo hace:

unsigned int y = x; 

El contenido de X es una copia literal, es decir, bit a bit a y. Esto significa que si inspecciona los valores brutos en la memoria de x y y, serán idénticos. Sin embargo si lo hace:

unsigned long long y1 = x; 

el valor de x será signo extendido antes de ser convertido a un unsigned long long. En el caso común cuando long long es 64 bits, esto significa que y1 es igual a 0xFFFFFFFFFFFFFFFB.

Es importante tener en cuenta lo que sucede al convertir a un tipo más grande. Un valor firmado que se envía a un valor firmado más grande se extenderá con signo. Esto no sucederá si el valor de la fuente no está firmado, por ejemplo .:

unsigned int z = y + 5; 
long long z1 = (long long)x + 5; // sign extended since x is signed 
long long z2 = (long long)y + 5; // not sign extended since y is unsigned 

z y z1 será igual a 0, pero z2 no lo hará. Esto puede remediarse mediante conversión del valor de firmado antes expandiéndolo:

long long z3 = (long long)(signed int)y + 5; 

o analógicamente si no desea que la extensión de signo que se produzca:

long long z4 = (long long)(unsigned int)x; 
+1

Pero la pregunta es sobre la conversión al tipo * unsigned *. Sin embargo, en la respuesta solo menciona conversiones a tipos * signed *. – AnT

+0

Propongo diferir, aunque enfoco un poco mi respuesta en las conversiones a los tipos con signo, ya que es allí donde hay dragones. Tampoco creo que mi respuesta merezca el voto negativo, pero soy parcial. –

+0

+1: para "complemento de dos", incluso si en realidad la redacción evasiva de C99 proporciona una definición que también funcionaría con un compilador que usaría, por ejemplo, BCD.Me pregunto si existe tal compilador de C de todos modos, hasta que se demuestre que está equivocado. Creo que todos los compiladores de C que existen actualmente usan dos complementos. – kriss

Cuestiones relacionadas