language-agnostic integer unsigned signed

language agnostic - Enteros versus Enteros Sin Firmar



language-agnostic integer (15)

¿Tengo razón al decir que la diferencia entre un entero con signo y sin signo es:

  1. Sin firmar puede contener un valor positivo mayor y ningún valor negativo.
  2. Sin firmar usa el bit inicial como parte del valor, mientras que la versión firmada usa el bit más a la izquierda para identificar si el número es positivo o negativo.
  3. Los enteros con signo pueden contener tanto números positivos como negativos.

¿Alguna otra diferencia?


  1. Sí, un entero sin signo puede almacenar un gran valor.
  2. No, hay diferentes maneras de mostrar valores positivos y negativos.
  3. Sí, el entero con signo puede contener valores positivos y negativos.

  1. Sí.

  2. Hay diferentes formas de representar enteros con signo. Lo más fácil de visualizar es usar el bit más a la izquierda como una bandera ( signo y magnitud ), pero más común es el complemento de dos . Ambos están en uso en la mayoría de los microprocesadores modernos: el punto flotante usa signo y magnitud, mientras que la aritmética de enteros usa el complemento de dos.


(en respuesta a la segunda pregunta) Al usar solo un bit de signo (y no el complemento de 2), puede terminar con -0. No es muy bonita.


Básicamente solo le preguntó por firmados y no firmados. No sé por qué la gente está agregando cosas extra en esto. Déjame decirte la respuesta.

  1. Sin firmar: Consiste solo en un valor positivo, es decir, de 0 a 255.

  2. Firmado: consiste tanto en valores negativos como positivos pero en diferentes formatos como

    • -1 a -128
    • 0 a +127

Y toda esta explicación es sobre el sistema numérico de 8 bits.


De acuerdo con lo que aprendimos en clase, los enteros con signo pueden representar tanto números positivos como negativos, mientras que los enteros sin signo son solo no negativos.

Por ejemplo, mirando un número de 8 bits :

valores sin firmar de 0 a 255

los valores firmados van desde -128 a 127


Debe utilizar enteros sin firmar al programar en sistemas integrados. En los bucles, cuando no hay necesidad de enteros con signo, el uso de enteros sin signo se guardará de forma segura para el diseño de dichos sistemas.


En términos generales eso es correcto. Sin saber más sobre por qué está buscando las diferencias, no puedo pensar en ningún otro elemento diferenciador entre firmado y sin firmar.


Es más probable que los enteros sin signo lo atrapen en una trampa en particular que los enteros con signo. La trampa proviene del hecho de que, si bien 1 y 3 de arriba son correctos, a ambos tipos de enteros se les puede asignar un valor fuera de los límites de lo que puede "retener" y se convertirá en silencio.

unsigned int ui = -1; signed int si = -1; if (ui < 0) { printf("unsigned < 0/n"); } if (si < 0) { printf("signed < 0/n"); } if (ui == si) { printf("%d == %d/n", ui, si); printf("%ud == %ud/n", ui, si); }

Cuando ejecute esto, obtendrá la siguiente salida aunque ambos valores se asignaron a -1 y se declararon de manera diferente.

signed < 0 -1 == -1 4294967295d == 4294967295d


La única diferencia garantizada entre un valor firmado y un valor sin signo en C es que el valor firmado puede ser negativo, 0 o positivo, mientras que un sin signo solo puede ser 0 o positivo. El problema es que C no define el formato de los tipos (por lo que no sabe que sus enteros están en el complemento de dos). Estrictamente hablando, los dos primeros puntos que mencionaste son incorrectos.


Los enteros con signo en C representan números. Si a y b son variables de tipos enteros con signo, el estándar nunca requerirá que un compilador haga que la expresión a+=b almacene en a cosa que no sea la suma aritmética de sus valores respectivos. Para estar seguro, si la suma aritmética no encajara en a procesador, es posible que el procesador no pueda ponerlo allí, pero el estándar no requeriría que el compilador truncara o envolviera el valor, ni hiciera otra cosa si los valores Superan los límites de sus tipos. Tenga en cuenta que si bien el estándar no lo requiere, las implementaciones de C pueden atrapar desbordamientos aritméticos con valores con signo.

Los enteros sin signo en C se comportan como anillos algebraicos abstractos de enteros que son módulos congruentes con una potencia de dos, excepto en escenarios que involucran conversiones o operaciones con tipos más grandes. La conversión de un número entero de cualquier tamaño a un tipo sin signo de 32 bits producirá el miembro correspondiente a las cosas que son congruentes con ese número entero mod 4,294,967,296. La razón por la que restar 3 de 2 produce 4,294,967,295 es que al agregar algo congruente a 3 a algo congruente a 4,294,967,295 se obtendrá algo congruente a 2.

Los tipos abstractos de anillos algebraicos son a menudo cosas útiles para tener; desafortunadamente, C usa la firmeza como el factor decisivo para determinar si un tipo debe comportarse como un anillo. Peor aún, los valores sin signo se tratan como números en lugar de miembros del anillo cuando se convierten a tipos más grandes, y los valores sin signo más pequeños que los int se convierten en números cuando se realiza una aritmética sobre ellos. Si v es un uint32_t que es igual a 4,294,967,294 , entonces v*=v; Debe hacer v=4 . Desafortunadamente, si int es de 64 bits, entonces no se sabe qué es v*=v; podría hacer.

Dado el estándar tal como es, sugeriría usar tipos sin signo en situaciones en las que uno quiere el comportamiento asociado con los anillos algebraicos, y tipos con signo cuando se quiere representar números. Es lamentable que C hiciera las distinciones como lo hizo, pero son lo que son.


Más allá de lo que otros han dicho, en C, no puede desbordar un entero sin signo; El comportamiento se define como módulo aritmético. Puede desbordar un entero con signo y, en teoría (aunque no en la práctica en los sistemas convencionales actuales), el desbordamiento podría desencadenar una falla (tal vez similar a una falla de división por cero).


Otra diferencia es cuando estás convirtiendo entre enteros de diferentes tamaños.

Por ejemplo, si está extrayendo un entero de un flujo de bytes (digamos 16 bits para simplificar), con valores sin signo, podría hacer:

i = ((int) b[j]) << 8 | b[j+1]

(Probablemente debería lanzar el byte, pero supongo que el compilador hará lo correcto)

Con los valores firmados, tendría que preocuparse por la extensión de firma y hacer:

i = (((int) b[i]) & 0xFF) << 8 | ((int) b[i+1]) & 0xFF


Sólo unos pocos puntos para completar:

  • esta respuesta es discutir solo representaciones enteras. Puede haber otras respuestas para el punto flotante;

  • La representación de un número negativo puede variar. El más común (en gran medida, hoy en día es casi universal) que se usa hoy es el complemento de dos . Otras representaciones incluyen el complemento de uno (bastante raro) y la magnitud con signo (muy poco frecuente, probablemente solo se usa en piezas de museo) que simplemente utiliza el bit alto como indicador de signo con los bits restantes que representan el valor absoluto del número.

  • Cuando se usa el complemento de dos, la variable puede representar un rango mayor (por uno) de números negativos que de números positivos. Esto se debe a que el cero se incluye en los números ''positivos'' (ya que el bit de signo no se establece en cero), pero no los números negativos. Esto significa que el valor absoluto del número negativo más pequeño no se puede representar.

  • al usar el complemento de uno o la magnitud con signo, puede tener el cero representado como un número positivo o negativo (lo cual es una de las dos razones por las que estas representaciones no se usan normalmente).


Todo excepto el punto 2 es correcto. Hay muchas notaciones diferentes para las inscripciones firmadas, algunas implementaciones usan la primera, otras usan la última y otras usan algo completamente diferente. Todo depende de la plataforma con la que estés trabajando.


Voy a entrar en diferencias en el nivel de hardware, en x86. Esto es en su mayoría irrelevante a menos que esté escribiendo un compilador o utilizando lenguaje ensamblador. Pero es bueno saberlo.

En primer lugar, x86 tiene soporte nativo para la representación complementaria de dos de los números firmados. Puede usar otras representaciones, pero esto requeriría más instrucciones y generalmente sería una pérdida de tiempo de procesador.

¿Qué quiero decir con "soporte nativo"? Básicamente, quiero decir que hay un conjunto de instrucciones que usa para los números sin firma y otro conjunto que usa para los números firmados. Los números no firmados se pueden colocar en los mismos registros que los números firmados y, de hecho, puede combinar instrucciones firmadas y no firmadas sin preocuparse por el procesador. Depende del compilador (o programador de ensamblajes) hacer un seguimiento de si un número está firmado o no, y usar las instrucciones apropiadas.

En primer lugar, los números complementarios de dos tienen la propiedad de que la suma y la resta son las mismas que para los números sin signo. No importa si los números son positivos o negativos. (Así que solo sigue adelante y ADD y SUB tus números sin preocupaciones).

Las diferencias comienzan a mostrarse cuando se trata de comparaciones. x86 tiene una forma simple de diferenciarlos: arriba / abajo indica una comparación sin signo y mayor / menor que indica una comparación con signo. (Por ejemplo, JAE significa "Saltar si está arriba o igual" y no está firmado).

También hay dos conjuntos de instrucciones de multiplicación y división para tratar con enteros con signo y sin signo.

Por último: si desea verificar, por ejemplo, el desbordamiento, lo haría de manera diferente para los números firmados y no firmados.