sirve - Dado que los caracteres de-128 a-1 son los mismos que de+128 a+255, entonces, ¿cuál es el punto de usar char sin signo?
unsigned long (5)
#include <stdio.h>
#include <conio.h>
int main()
{
char a=-128;
while(a<=-1)
{
printf("%c/n",a);
a++;
}
getch();
return 0;
}
El resultado del código anterior es el mismo que el del código siguiente
#include <stdio.h>
#include <conio.h>
int main()
{
unsigned char a=+128;
while(a<=+254)
{
printf("%c/n",a);
a++;
}
getch();
return 0;
}
Entonces, ¿por qué usamos unsigned char
y signed char
?
Con caracteres de impresión, no hay diferencia:
La función printf()
usa "%c"
y toma el argumento int
y lo convierte en unsigned char
y luego lo imprime.
char a;
printf("%c/n",a); // a is converted to int, then passed to printf()
unsigned char ua;
printf("%c/n",ua); // ua is converted to int, then passed to printf()
Con valores de impresión (números): diferencia cuando el sistema usa un char
que está firmado :
char a = -1;
printf("%d/n",a); // --> -1
unsigned char ua = -1;
printf("%d/n",ua); // --> 255 (Assume 8-bit unsigned char)
Nota: las máquinas raras tendrán el mismo tamaño que las de char
y se aplicarán otras preocupaciones.
Entonces, si el código usa a
como un número en lugar de un carácter, las diferencias de impresión son significativas.
K & R, capítulo y versículo, p. 43 y 44:
Hay un punto sutil sobre la conversión de caracteres a enteros. El idioma no especifica si las variables de tipo char son cantidades firmadas o sin firmar. Cuando un char se convierte en un int, ¿puede alguna vez producir un entero negativo? La respuesta varía de una máquina a otra, lo que refleja las diferencias en la arquitectura. En algunas máquinas, un char cuyo bit más a la izquierda es 1 se convertirá en un entero negativo ("extensión de signo"). En otros, un char se promueve a un int agregando ceros en el extremo izquierdo, y por lo tanto siempre es positivo. [...] Los patrones de bits arbitrarios almacenados en las variables de caracteres pueden parecer negativos en algunas máquinas, pero positivas en otras. Para la portabilidad, especifique firmado o sin firmar si los datos sin carácter deben almacenarse en variables char.
La representación de bits de un número es lo que almacena la computadora, pero no significa nada sin que alguien (o algo) le imponga un patrón.
La diferencia entre el unsigned char
y los patrones de caracteres con unsigned char
es la forma en que interpretamos los bits del conjunto. En un caso, decidimos que cero es el número más pequeño y podemos agregar bits hasta que lleguemos a 0xFF
o al 11111111
binario. En el otro caso, decidimos que 0x80
es el número más pequeño y podemos agregar bits hasta que lleguemos a 0x7F
.
La razón por la que tenemos la manera divertida de representar los números con signo (el último patrón) es porque coloca cero 0x00
aproximadamente en el medio de la secuencia, y porque 0xFF
(que es -1, justo antes de cero) más 0x01
(que es 1, justo después de cero) sumar para llevar hasta que todos los bits se lleven al extremo superior dejando 0x00 (-1 + 1 = 0)
. Del mismo modo -5 + 5 = 0
por el mismo mechanisim.
Para divertirse, hay muchos patrones de bits que significan cosas diferentes. Por ejemplo, 0x2a
podría ser lo que llamamos un "número" o podría ser un carácter *
. Depende del contexto que elijamos imponer en los patrones de bits.
Porque el unsigned char
se utiliza para un entero de un byte en C89
.
Tenga en cuenta que hay tres tipos distintos de caracteres relacionados en C89
: char
, signed char
, unsigned char
.
Para el tipo de carácter, se usa char
.
unsigned char
y el unsigned char
se usan para los enteros de un byte, como el short
para los enteros de dos bytes. En realidad, no debería usar signed char
o unsigned char
para caracteres. Tampoco deberías confiar en el orden de esos valores.
Se crean diferentes tipos para decirle al compilador cómo "entender" la representación de bits de uno o más bytes. Por ejemplo, supongamos que tengo un byte que contiene 0xFF
. Si se interpreta como un signed char
, es -1; si se interpreta como un unsigned char
, es 255.
En su caso, a
, independientemente de si está firmado o no, se promueve integral a int
y se pasa a printf()
, que más tarde lo convierte implícitamente en unsigned char
antes de imprimirlo como un carácter.
Pero consideremos otro caso:
#include <stdio.h>
#include <string.h>
int main(void)
{
char a = -1;
unsigned char b;
memmove(&b, &a, 1);
printf("%d %u", a, b);
}
Es prácticamente aceptable escribir simplemente printf("%d %u", a, a);
. memmove()
se usa solo para evitar un comportamiento indefinido.
Su salida en mi máquina es:
-1 4294967295
Además, piensa en esta ridícula pregunta:
Supongamos
sizeof (int) == 4
, ya que las matrices de caracteres(unsigned char[]){UCHAR_MIN, UCHAR_MIN, UCHAR_MIN, UCHAR_MIN}
a(unsigned char[]){UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}
son las mismas que lasunsigned int
s deUINT_MIN
aUINT_MAX
, entonces, ¿qué sentido tiene usarunsigned int
?