Valores sin firmar en C

6 minutos de lectura

avatar de usuario
villablanca

Tengo el siguiente código:

#include <stdio.h>

int main() {
    unsigned int a = -1;
    int b = -1;
    printf("%x\n", a);
    printf("%x\n", b);

    printf("%d\n", a);
    printf("%d\n", b);

    printf("%u\n", a);
    printf("%u\n", b);
    return 0;
}

La salida es:

ffffffff
ffffffff
-1
-1
4294967295
4294967295

Puedo ver que un valor se interpreta como firmado o sin firmar según el valor pasado a printf función. En ambos casos, los bytes son los mismos (ffffffff). Entonces, ¿cuál es el unsigned palabra para?

  • Ver: Complemento a dos – Wikipedia, la enciclopedia libre La respuesta corta es “si el bit más significativo es 1se interpreta como un negativo entero”.

    –David C. Rankin

    2 de septiembre de 2015 a las 4:51


  • @rvillablanca “si puedo ver una var firmada impresa como firmada o sin firmar” – no puede, imprimiendo un valor sin firmar usando %d e imprimiendo un valor firmado usando %u o %x es comportamiento indefinido.

    – El Croissant Paramagnético

    2 de septiembre de 2015 a las 5:13

  • Algunas de sus declaraciones de printf son UB, que domina esta pregunta.

    –David Heffernan

    2 de septiembre de 2015 a las 5:45

  • Es un comportamiento indefinido. Nadie puede entender lo que quiere decir con “imprimir ffffffff se puede imprimir como firmado -1 o sin firmar 4294967295”. El mismo patrón de bits se puede tratar como firmado o sin firmar en printf usando el formato correspondiente si convierte el valor al tipo correcto primero.

    – phuclv

    2 de septiembre de 2015 a las 5:53

  • posible duplicado de ¿Qué sucede cuando asigno un valor negativo a un int sin firmar?

    – Bo Person

    2 de septiembre de 2015 a las 7:43

avatar de usuario
chux – Reincorporar a Monica

Asignar un int -1 a una unsigned: Como -1 no entra en el rango [0...UINT_MAX]múltiplos de UINT_MAX+1 se agregan hasta que la respuesta está dentro del rango. Evidentemente UINT_MAX es pow(2,32)-1 or 429496725 en la máquina de OP entonces a tiene el valor de 4294967295.

unsigned int a = -1;

los "%x", "%u" especificador espera una coincidencia unsigned. Dado que estos no coinciden, “si una especificación de conversión no es válida, el comportamiento no está definido. Si algún argumento no es del tipo correcto para la especificación de conversión correspondiente, el el comportamiento no está definido.” C11 §7.21.6.1 9. El especificador printf no cambia b.

printf("%x\n", b);  // UB
printf("%u\n", b);  // UB

los "%d" especificador espera una coincidencia int. Dado que estos no coinciden, más UB.

printf("%d\n", a);  // UB

Dado un comportamiento indefinido, las conclusiones no son compatibles.


en ambos casos, los bytes son los mismos (ffffffff).

Incluso con el mismo patrón de bits, diferentes tipos pueden tener valores diferentes. ffffffff como un unsigned tiene el valor de 4294967295. Como int, dependiendo de la codificación de enteros con signo, tiene el valor de -1, -2147483647 o TBD. Como un float puede ser un YAYA.

¿Para qué sirve la palabra sin signo?

unsigned almacena un número entero en el rango [0 ... UINT_MAX]. Nunca tiene un valor negativo. Si el código necesita un número no negativo, utilice unsigned. Si el código necesita un número de conteo que puede ser +, – o 0, use int.


Actualización: para evitar una advertencia del compilador sobre la asignación de un firmado int para unsigned, utilice el siguiente. Esto es un unsigned 1u siendo negado – que está bien definido como arriba. El efecto es el mismo que un -1pero transmite al compilador intenciones directas.

unsigned int a = -1u;

  • Su afirmación sobre la UB es incorrecta. Vuelva a leer los párrafos anteriores al que citó. TL; DR: cualquier especificador de conversión que siga la gramática es “válido”. En otras palabras en printf("%d", "foo") el especificador “%d” es válido, en el sentido al que se refiere el párrafo citado. Por supuesto, tratar de imprimir una cadena como un int es UB, pero no por la razón por la que parece pensar. Más bien, “se realiza la promoción o conversión de tipo adecuada, si está permitida” y dado que no se permite ninguna promoción o conversión de tipo de cadena a int, se convierte en UB.

    – AñorZaken

    24 de octubre de 2017 a las 12:57

  • @AnorZaken Respuesta modificada para enfatizar que el especificador printf y el tipo de argumento no coinciden.

    – chux – Reincorporar a Monica

    24 de octubre de 2017 a las 14:07

  • Err, ¿por qué el especificador %u no estaría definido para un entero sin signo? b?

    – Colombo

    12 de mayo de 2020 a las 9:22

  • @Columbo con int b = -1;, b no es un entero sin signopero un int con el valor de -1. La impresión con un especificador que no coincide es UB: hay una excepción con números positivos, pero eso no se aplica aquí.

    – chux – Reincorporar a Monica

    12 de mayo de 2020 a las 14:47

  • Eso es tan malinterpretable, porque solo cita la definición de ay luego proceda a usar b. Cite ambas definiciones en su respuesta, por favor.

    – Colombo

    12 de mayo de 2020 a las 15:14


Teniendo unsigned en la declaración de variables es más útil para los propios programadores; no trate las variables como negativas. Como habrás notado, ambos -1 y 4294967295 tienen exactamente la misma representación de bits para un entero de 4 bytes. Se trata de cómo quieres tratar o ver ellos.

La declaración unsigned int a = -1; se está convirtiendo -1 en complemento a dos y asignando la representación de bits en a. los printf() especificador x, d y u están mostrando cómo la representación de bits almacenada en la variable a parece en otro formato.

avatar de usuario
Santosh A

Cuando inicializas unsigned int a to -1; significa que usted está almacenando el 2's complemento de -1 en la memoria de a.
que no es más que 0xffffffff o 4294967295.

Por lo tanto, cuando lo imprimes usando %x or %u especificador de formato obtienes esa salida.

Especificando el signo de una variable para decidir el límite mínimo y máximo de valor que se puede almacenar.

como con unsigned int: el rango es de 0 to 4,294,967,295 y int: el rango es de -2,147,483,648 to 2,147,483,647

Para obtener más información sobre la firma, consulte esta

avatar de usuario
ARAVINTHKUMAR J

En el hexadecimal no puede obtener un valor negativo. Entonces lo muestra como ffffffff.

La ventaja de usar la versión sin firmar (cuando sabe que los valores contenidos no serán negativos) es que a veces la computadora detectará errores por usted (el programa “choque” cuando una valor negativo se asigna a la variable).

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad