En C / C ++, ¿para qué unsigned char
se utiliza? ¿Cómo es diferente de un regular char
?
En C / C ++, ¿para qué unsigned char
se utiliza? ¿Cómo es diferente de un regular char
?
Respuestas:
En C ++, hay tres tipos de caracteres distintos :
char
signed char
unsigned char
Si está utilizando tipos de caracteres para el texto , use el no calificado char
:
'a'
o '0'
."abcde"
También funciona como un valor numérico, pero no se especifica si ese valor se trata como con signo o sin signo. Tenga cuidado con las comparaciones de caracteres a través de las desigualdades, aunque si se limita a ASCII (0-127) está a salvo.
Si está utilizando tipos de caracteres como números , use:
signed char
, que le da al menos el rango de -127 a 127. (-128 a 127 es común)unsigned char
, que le da al menos el rango de 0 a 255."Al menos", porque el estándar C ++ solo proporciona el rango mínimo de valores que cada tipo numérico debe cubrir. sizeof (char)
se requiere que sea 1 (es decir, un byte), pero un byte podría ser, en teoría, por ejemplo, 32 bits. sizeof
seguiría informando su tamaño como1
, lo que significa que podría tener sizeof (char) == sizeof (long) == 1
.
sizeof
porque no es una función sino un operador. Es incluso mejor estilo omitir el paréntesis cuando se toma el tamaño de una variable. sizeof *p
o sizeof (int)
. Esto deja en claro rápidamente si se aplica a un tipo o variable. Del mismo modo, también es redundante poner paréntesis después return
. No es una función.
char
: es el tipo de literales de caracteres como 'a'
o '0'
". es cierto en C ++ pero no en C. En C, 'a'
es un int
.
Esto depende de la implementación, ya que el estándar C NO define la firma de char
. Dependiendo de la plataforma, char puede ser signed
o unsigned
, por lo que debe solicitar explícitamente signed char
o unsigned char
si su implementación depende de ello. Solo úselo char
si tiene la intención de representar caracteres de cadenas, ya que esto coincidirá con lo que su plataforma pone en la cadena.
La diferencia entre signed char
y unsigned char
es como era de esperar. En la mayoría de las plataformas, signed char
habrá un número de complemento de dos de 8 bits que va de -128
a 127
, y unsigned char
será un entero sin signo de 8 bits ( 0
a 255
). Tenga en cuenta que el estándar NO requiere que los char
tipos tengan 8 bits, solo ese sizeof(char)
retorno 1
. Puede obtener el número de bits en un char con CHAR_BIT
in limits.h
. Sin 8
embargo, hay pocas plataformas, si es que hay alguna, en las que esto sea algo diferente .
Hay un buen resumen de este problema aquí .
Como otros han mencionado desde que publiqué esto, es mejor que uses int8_t
y uint8_t
si realmente quieres representar números enteros pequeños.
CHAR_BIT
se requiere que tenga al menos 8 bits según el estándar.
Debido a que siento que es realmente necesario, solo quiero establecer algunas reglas de C y C ++ (son las mismas en este sentido). Primero, todos los bits de unsigned char
participan en la determinación del valor de cualquier objeto char sin firmar. En segundo lugar, unsigned char
se declara explícitamente sin firmar.
Ahora, tuve una discusión con alguien sobre lo que sucede cuando convierte el valor -1
de tipo int a unsigned char
. Rechazó la idea de que el resultado unsigned char
tiene todos sus bits establecidos en 1, porque estaba preocupado por la representación de signos. Pero no tiene que hacerlo. Inmediatamente después de esta regla, la conversión hace lo que se pretende:
Si el nuevo tipo no tiene signo, el valor se convierte agregando o restando 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. (
6.3.1.3p2
en un borrador C99)
Esa es una descripción matemática. C ++ lo describe en términos de cálculo de módulo, que cede a la misma regla. De todos modos, lo que no está garantizado es que todos los bits en el entero -1
sean uno antes de la conversión. Entonces, ¿qué tenemos para poder afirmar que el resultado unsigned char
tiene todos sus CHAR_BIT
bits convertidos en 1?
UCHAR_MAX+1
a -1
rendirá un valor en el rango, a saber,UCHAR_MAX
Eso es suficiente, en realidad! Así que cada vez que quieras tener uno unsigned char
con todos sus bits, lo haces
unsigned char c = (unsigned char)-1;
También se deduce que una conversión no es solo truncar bits de orden superior. El evento afortunado para el complemento de dos es que es solo un truncamiento allí, pero lo mismo no es necesariamente cierto para otras representaciones de signos.
UCHAR_MAX
?
(unsigned type)-1
es una especie de idioma. ~0
no lo es
int x = 1234
y char *y = &x
. Representación binaria de 1234
is 00000000 00000000 00000100 11010010
. Mi máquina es little endian, por lo que la invierte y la almacena en memoria. 11010010 00000100 00000000 00000000
LSB es lo primero. Ahora parte principal. Si uso printf("%d" , *p)
. printf
leerá el primer byte 11010010
solo el resultado es -46
pero 11010010
es 210
así, ¿por qué se imprime -46
? Estoy realmente confundido, supongo que una promoción de char a entero está haciendo algo, pero no lo sé.
Como, por ejemplo, usos de caracteres sin firmar :
unsigned char
A menudo se usa en gráficos de computadora, que muy a menudo (aunque no siempre) asigna un solo byte a cada componente de color. Es común ver un color RGB (o RGBA) representado como 24 (o 32) bits, cada uno unsigned char
. Como los unsigned char
valores caen en el rango [0,255], los valores generalmente se interpretan como:
Entonces terminaría con rojo RGB como (255,0,0) -> (100% rojo, 0% verde, 0% azul).
¿Por qué no usar a signed char
? El cambio aritmético y de bits se vuelve problemático. Como ya se explicó, signed char
el rango de a se desplaza esencialmente por -128. Un método muy simple e ingenuo (en su mayoría no utilizado) para convertir RGB a escala de grises es promediar los tres componentes de color, pero esto tiene problemas cuando los valores de los componentes de color son negativos. El rojo (255, 0, 0) promedia a (85, 85, 85) cuando se usa la unsigned char
aritmética. Sin embargo, si los valores fueran signed char
s (127, -128, -128), terminaríamos con (-99, -99, -99), que sería (29, 29, 29) en nuestro unsigned char
espacio, lo cual es incorrecto .
Si desea utilizar un carácter como un entero pequeño, la forma más segura de hacerlo es con los tipos int8_t
y uint8_t
.
int8_t
y uint8_t
son opcionales y no están definidos en arquitecturas donde el tamaño del byte no es exactamente de 8 bits. Por el contrario, signed char
y unsigned char
siempre están disponibles y garantizados para contener al menos 8 bits. Puede ser una forma común pero no la más segura .
signed char
y unsigned char
? ¿O recomendaría una mejor alternativa "más segura" en ese caso particular? Por ejemplo, para quedarse con los tipos enteros "reales" signed int
y en su unsigned int
lugar por alguna razón?
signed char
y unsigned char
es portátil para todas las implementaciones conformes y ahorrará espacio de almacenamiento, pero puede causar un aumento en el tamaño del código. En algunos casos, se ahorraría más espacio de almacenamiento al almacenar valores pequeños en campos de bits o bits individuales de tipos enteros regulares. No hay una respuesta absoluta a esta pregunta, la pertinencia de este enfoque depende del caso específico en cuestión. Y esta respuesta no aborda la pregunta de todos modos.
char
y unsigned char
no se garantiza que sean de 8 bits en todas las plataformas; se garantiza que serán de 8 bits o más. Algunas plataformas tienen bytes de 9 bits, 32 bits o 64 bits . Sin embargo, las plataformas más comunes en la actualidad (Windows, Mac, Linux x86, etc.) tienen bytes de 8 bits.
signed char
tiene un rango de -128 a 127; unsigned char
tiene rango de 0 a 255.
char
será equivalente a char firmado o no firmado, dependiendo del compilador, pero es un tipo distinto.
Si está utilizando cadenas de estilo C, solo utilícelas char
. Si necesita usar caracteres para aritmética (bastante raro), especifique con o sin signo explícitamente para la portabilidad.
Un unsigned char
es un valor de byte sin signo (0 a 255). Puede estar pensando char
en términos de ser un "personaje", pero en realidad es un valor numérico. El regular char
está firmado, por lo que tiene 128 valores, y estos valores se asignan a caracteres mediante codificación ASCII. Pero en cualquier caso, lo que está almacenando en la memoria es un valor de byte.
En términos de valores directos, se utiliza un carácter normal cuando se sabe que los valores están entre CHAR_MIN
y CHAR_MAX
mientras que un carácter sin signo proporciona el doble del rango en el extremo positivo. Por ejemplo, si CHAR_BIT
es 8, el rango de regular char
solo se garantiza que sea [0, 127] (porque puede estar firmado o no) mientras unsigned char
que será [0, 255] y signed char
será [-127, 127].
En términos de para qué se utiliza, los estándares permiten que los objetos de POD (datos antiguos simples) se conviertan directamente en una matriz de caracteres sin signo. Esto le permite examinar la representación y los patrones de bits del objeto. La misma garantía de juego seguro no existe para char o char firmado.
unsigned char
, no una matriz específicamente, y cualquier "conversión" solo se define formalmente copiando del objeto a una matriz real declarada de unsigned char
y luego inspeccionando el último. No está claro si el OR se puede reinterpretar directamente como una matriz de este tipo, con las tolerancias para la aritmética del puntero que implicaría, es decir, si la "secuencia" ==
"matriz" en este uso. Hay un problema central # 1701 abierto con la esperanza de aclarar esto. Afortunadamente, ya que esta ambigüedad realmente me está molestando recientemente.
unsigned char
de la OR y luego continuar usando ++ptr
desde allí para leer cada byte ... pero AFAICT, no se define específicamente como permitido, por lo que estamos Dejó inferir que está "probablemente bien" en muchos otros pasajes (y en muchos sentidos, la mera existencia de memcpy
) en el Estándar, similar a un rompecabezas. Lo cual no es ideal. Bueno, tal vez la redacción mejore eventualmente. Aquí está el problema de CWG que mencioné pero que no tenía espacio para vincular: open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1701
unsigned char
es el corazón de todos los trucos. En casi TODO el compilador para TODAS las plataformas, un unsigned char
es simplemente un byte y un entero sin signo de (generalmente) 8 bits que pueden tratarse como un entero pequeño o un paquete de bits.
En adicción, como alguien más ha dicho, el estándar no define el signo de un personaje. por lo que tiene 3 distintos char
tipos: char
, signed char
, unsigned char
.
Si te gusta usar varios tipos de longitud y de signo específico, usted es probablemente mejor con uint8_t
, int8_t
, uint16_t
, etc, simplemente porque hacen exactamente lo que dicen.
Algunos buscadores en Google encontraron esto , donde la gente tuvo una discusión sobre esto.
Un carácter sin signo es básicamente un solo byte. Por lo tanto, usaría esto si necesita un byte de datos (por ejemplo, tal vez quiera usarlo para activar y desactivar indicadores para que se pasen a una función, como se hace a menudo en la API de Windows).
Un personaje sin signo utiliza el bit que está reservado para el signo de un personaje normal como otro número. Esto cambia el rango a [0 - 255] en lugar de [-128 - 127].
Generalmente, los caracteres sin signo se usan cuando no desea una señal. Esto marcará una diferencia al hacer cosas como cambiar bits (shift extiende el signo) y otras cosas cuando se trata de un carácter como un byte en lugar de usarlo como un número.
citado del libro "the c programa laugage":
El calificador signed
o unsigned
se puede aplicar a char o cualquier número entero. los números sin signo son siempre positivos o cero, y obedecen las leyes del módulo aritmético 2 ^ n, donde n es el número de bits en el tipo. Entonces, por ejemplo, si los caracteres son de 8 bits, las variables de caracteres sin signo tienen valores entre 0 y 255, mientras que los caracteres con signo tienen valores entre -128 y 127 (en una máquina complementaria de dos). Si los caracteres simples son con signo o sin signo es máquina independientes, pero los caracteres imprimibles son siempre positivos.
signed char
y unsigned char
ambos representan 1byte, pero tienen diferentes rangos.
Type | range
-------------------------------
signed char | -128 to +127
unsigned char | 0 to 255
En signed char
si tenemos en cuenta char letter = 'A'
, 'A' es representar binaria de 65 en ASCII/Unicode
, 65 Si se puede almacenar, -65 también se pueden almacenar. No hay valores binarios negativos ASCII/Unicode
allí para no tener que preocuparse por los valores negativos.
Ejemplo
#include <stdio.h>
int main()
{
signed char char1 = 255;
signed char char2 = -128;
unsigned char char3 = 255;
unsigned char char4 = -128;
printf("Signed char(255) : %d\n",char1);
printf("Unsigned char(255) : %d\n",char3);
printf("\nSigned char(-128) : %d\n",char2);
printf("Unsigned char(-128) : %d\n",char4);
return 0;
}
Salida -:
Signed char(255) : -1
Unsigned char(255) : 255
Signed char(-128) : -128
Unsigned char(-128) : 128