M310
Cuando necesite almacenar en la memoria algunos datos sin procesar, por ejemplo, de una secuencia, ¿es mejor usar una matriz de char
o de unsigned char
? yo siempre usaba char
pero en el trabajo dicen que es mejor unsigned char
y no se porque
tony delroy
ACTUALIZACIÓN: C++17 introducido std::byte
que es más adecuado para los búferes de datos “en bruto” que para usar cualquier tipo de char
.
Para versiones anteriores de C++:
-
unsigned char
enfatiza que los datos no son “solo” texto -
si tiene lo que efectivamente son datos de “bytes” de, por ejemplo, un flujo comprimido, un archivo de copia de seguridad de la tabla de la base de datos, una imagen ejecutable, un jpeg … entonces
unsigned
es apropiado para la connotación de datos binarios mencionada anteriormente-
unsigned
funciona mejor para algunas de las operaciones que podría querer hacer en datos binarios, por ejemplo, hay comportamientos indefinidos y definidos por la implementación para algunas operaciones de bits en tipos firmados, yunsigned
los valores se pueden usar directamente como índices en matrices -
no puedes pasar accidentalmente un
unsigned char*
a una función esperandochar*
y operarlo como presunto texto -
en estas situaciones, por lo general, es más natural pensar que los valores están en el rango de 0 a 255, después de todo, ¿por qué el bit de “signo” debería tener un tipo de significado diferente al de los otros bits en los datos?
-
-
si está almacenando “datos sin procesar” que, a nivel de lógica/diseño de la aplicación, son datos numéricos de 8 bits, entonces, por supuesto, elija cualquiera
unsigned
o explícitamentesigned
char
según corresponda a sus necesidades
En lo que respecta a la estructura del búfer, no hay diferencia: en ambos casos se obtiene un tamaño de elemento de un byte, exigido por el estándar.
Quizás la diferencia más importante que obtiene es el comportamiento que ve cuando accede a los elementos individuales del búfer, por ejemplo, para imprimir. Con char
obtiene un comportamiento firmado o no firmado definido por la implementación; con unsigned char
siempre ves un comportamiento sin firmar. Esto se vuelve importante si desea imprimir los bytes individuales de su búfer de “datos sin procesar”.
Otra buena alternativa para el uso de búferes es el entero de ancho exacto uint8_t
. Se garantiza que tiene el mismo ancho que unsigned char
su nombre requiere menos tipeo y le dice al lector que no está diseñado para usar los elementos individuales del búfer como información basada en caracteres.
pablo francisco perez hidalgo
Internamente, es exactamente lo mismo: cada elemento es un byte. La diferencia se da cuando se opera con esos valores.
Si su rango de valores es [0,255] Deberías usar unsigned char
pero si es [-128,127] entonces deberías usar signed char
.
Supongamos que está utilizando el primer rango (signed char
), entonces puede realizar la operación 100+100
. De lo contrario, esa operación se desbordará y le dará un valor inesperado.
Dependiendo de su compilador o tipo de máquina, char
puede estar sin firmar o firmado de forma predeterminada: ¿Char está firmado o sin firmar de forma predeterminada? Así teniendo char
los rangos descritos para los casos anteriores.
Si está usando este búfer solo para almacenar datos binarios sin operar con él, no hay diferencia entre usar char
o unsigned char
.
EDITAR
Tenga en cuenta que incluso puede cambiar el valor predeterminado char
para la misma máquina y compilador usando las banderas del compilador:
-funsigned-char Deja que el tipo char no esté firmado, como char sin firmar.
Cada tipo de máquina tiene un valor predeterminado para lo que debe ser char. Es como un carácter sin firmar de forma predeterminada o como un carácter firmado de forma predeterminada. Idealmente, un programa portátil siempre debe usar caracteres firmados o caracteres sin firmar cuando depende de la firma de un objeto. Pero muchos programas han sido escritos para usar caracteres simples y esperan que estén firmados, o esperan que no estén firmados, dependiendo de las máquinas para las que fueron escritos. Esta opción, y su inversa, le permiten hacer que dicho programa funcione con el valor predeterminado opuesto.
El tipo char siempre es un tipo distinto de cada uno de char con signo o sin signo, aunque su comportamiento siempre es como uno de esos dos.
-
Asumes
char
está firmado. Entonces, las partes de “rango” y “desbordamiento” no son necesariamente ciertas.– PP
12 de junio de 2014 a las 9:51
-
“si esto es [-127,127] usar
char
.”char
también podría no estar firmado, si necesita firmar, usesigned char
. “… darte un número negativo”. Tal vez, tal vez no, el desbordamiento firmado es UB.– Baum mit Augen
♦12 de junio de 2014 a las 9:53
-
@BaummitAugen Es cierto, pero en ese caso OP no debería esperar obtener el valor deseado.
– Pablo Francisco Pérez Hidalgo
12 de junio de 2014 a las 9:56
Como dijo @Pablo en su respuesta, la razón clave es que si está haciendo aritmética en los bytes, obtendrá las respuestas ‘correctas’ si declara los bytes como unsigned char
: quieres (en el ejemplo de Pablo) 100 + 100 para sumar 200; si haces esa suma con signed char
(lo que podría hacer por accidente si char
en su compilador está firmado) no hay garantía de eso, está buscando problemas.
Otra razón importante es que puede ayudar a documentar su código, si es explícito acerca de qué tipos de datos son qué. Es útil declarar
typedef unsigned char byte
o mejor
#include <stdint.h>
typedef uint8_t byte
Usando byte
a partir de entonces hace que quede un poco más claro cuál es la intención de su programa. Dependiendo de cuán paranoico sea su compilador (-Wall
es tu amigo), este puede que incluso causar una advertencia de tipo si das un byte*
argumento a un char*
argumento de la función, lo que le incita a pensar un poco más detenidamente si está haciendo lo correcto.
Un ‘carácter’ es fundamentalmente una cosa bastante diferente de un ‘byte’. C pasa a difuminar la distinción (porque en el nivel de C, en un mundo mayormente ASCII, la distinción no importa en muchos casos). Este desenfoque no siempre es útil, pero al menos es una buena higiene intelectual para mantener la diferencia clara en tu cabeza.
Por lo general, es mejor usar char
pero hace tan poca diferencia que no importa. Son datos sin procesar, por lo que simplemente debe pasarlos como tales en lugar de intentar trabajar con ellos a través de char
punteros de un tipo u otro. Ya que char
es el tipo de datos nativo, tiene más sentido usar esto en lugar de imaginar que está forzando sus datos en un tipo u otro.
Comunidad
Si usa caracteres sin firmar, solo tomará caracteres ASCII válidos, ya que su rango será de -127 a +127.
y puede encontrar una diferencia completa entre char y los detalles de char sin firmar en esta pregunta.
diff bet char y char sin firmar
y se puede ver la tabla aquí.
Antonio
Si puede trabajar con C++17, hay un tipo std::byte que es más apropiado para trabajar con datos sin procesar. Solo tiene definidos operadores lógicos bit a bit.
si es un flujo de cadena, entonces estaría bien usarlo
char
formación. para otros datos brutos numéricos (por ejemplo, hexadecimales, bits), es mejor usarunsigned
variables para que no tenga que lidiar con el bit de signo– Iósif Murariu
12 de junio de 2014 a las 9:43