De vez en cuando, alguien en SO señala que char
(también conocido como 'byte') no es necesariamente de 8 bits .
Parece que 8 bits char
es casi universal. Pensé que para las plataformas convencionales, es necesario tener un bit de 8 bits char
para garantizar su viabilidad en el mercado.
Tanto ahora como históricamente, ¿qué plataformas usan una char
que no sea de 8 bits y por qué diferirían de los 8 bits "normales"?
Al escribir código y pensar en el soporte multiplataforma (por ejemplo, para bibliotecas de uso general), ¿qué tipo de consideración vale la pena dar a las plataformas que no son de 8 bits char
?
En el pasado me he encontrado con algunos DSP de dispositivos analógicos para los cuales char
es de 16 bits. Los DSP son un poco de arquitectura de nicho, supongo. (Por otra parte, en ese momento, el ensamblador codificado a mano venció fácilmente lo que los compiladores de C disponibles podían hacer, por lo que realmente no obtuve mucha experiencia con C en esa plataforma).
fuente
Respuestas:
char
también es de 16 bits en los DSP C54x de Texas Instruments, que aparecieron, por ejemplo, en OMAP2. Hay otros DSP con 16 y 32 bitschar
. Creo que incluso escuché sobre un DSP de 24 bits, pero no recuerdo qué, así que tal vez lo imaginé.Otra consideración es que los mandatos POSIX
CHAR_BIT == 8
. Entonces, si está utilizando POSIX, puede asumirlo. Si alguien más tarde necesita portar su código a una implementación cercana de POSIX, resulta que tiene las funciones que usa pero un tamaño diferentechar
, esa es su mala suerte.Sin embargo, en general, creo que casi siempre es más fácil solucionar el problema que pensarlo. Solo escribe
CHAR_BIT
. Si desea un tipo exacto de 8 bits, useint8_t
. Su código no se compilará ruidosamente en implementaciones que no proporcionan uno, en lugar de usar en silencio un tamaño que no esperaba. Por lo menos, si llego a un caso en el que tengo una buena razón para asumirlo, entonces lo afirmaría.fuente
assert()
(si eso es lo que quisiste decir), usaría#if CHAR_BIT != 8
...#error "I require CHAR_BIT == 8"
...#endif
static_assert()
?No es tanto que "valga la pena considerar" algo, sino que está jugando según las reglas. En C ++, por ejemplo, el estándar dice que todos los bytes tendrán "al menos" 8 bits. Si su código supone que los bytes tienen exactamente 8 bits, está violando el estándar.
Esto puede parecer una tontería ahora - " por supuesto todos los bytes tienen 8 bits!" Pero muchas personas muy inteligentes han confiado en suposiciones que no eran garantías, y luego todo se rompió. La historia está repleta de tales ejemplos.
Por ejemplo, la mayoría de los desarrolladores de principios de los 90 suponían que un retraso de temporización de CPU sin operación particular que tomaba un número fijo de ciclos tomaría una cantidad fija de tiempo de reloj, porque la mayoría de las CPU de consumo tenían una potencia aproximadamente equivalente. Desafortunadamente, las computadoras se hicieron más rápidas muy rápidamente. Esto generó el surgimiento de cajas con botones "Turbo", cuyo propósito, irónicamente, era ralentizar la computadora para que los juegos que usaran la técnica de retardo de tiempo pudieran jugarse a una velocidad razonable.
Un comentarista preguntó en qué parte del estándar dice que char debe tener al menos 8 bits. Está en la sección 5.2.4.2.1 . Esta sección define
CHAR_BIT
el número de bits en la entidad direccionable más pequeña y tiene un valor predeterminado de 8. También dice:Por lo tanto, cualquier número igual a 8 o superior es adecuado para la sustitución por una implementación en
CHAR_BIT
.fuente
char
ya que hay más de 64 de ellos pero menos de 128, por lo que 7 bits serían suficientes.Las máquinas con arquitecturas de 36 bits tienen bytes de 9 bits. Según Wikipedia, las máquinas con arquitecturas de 36 bits incluyen:
fuente
Algunos de los cuales estoy al tanto:
fuente
char
tipo? Sé que las bibliotecas del sistema solo admiten las versiones de caracteres anchos de las funciones que toman cadenas, y que al menos algunas versiones de WinCE eliminaron las funciones de cadena ANSI como strlen, para evitar que maneje cadenas de caracteres char. ¿Pero realmente no tenía un tipo de char en absoluto? ¿Qué fuesizeof(TCHAR)
? ¿Qué tipo regresó malloc? ¿Cómo sebyte
implementó el tipo Java ?No existe un código completamente portátil. :-)
Sí, puede haber varios tamaños de bytes / caracteres. Sí, puede haber implementaciones de C / C ++ para plataformas con valores altamente inusuales de
CHAR_BIT
yUCHAR_MAX
. Sí, a veces es posible escribir código que no depende del tamaño del carácter.Sin embargo, casi cualquier código real no es independiente. Por ejemplo, puede estar escribiendo un código que envía mensajes binarios a la red (el protocolo no es importante). Puede definir estructuras que contengan campos necesarios. Entonces tienes que serializarlo. La copia binaria de una estructura en un búfer de salida no es portátil: generalmente no conoce el orden de bytes de la plataforma ni la alineación de los miembros de la estructura, por lo que la estructura solo contiene los datos, pero no describe la forma en que los datos deben ser serializados. .
Okay. Puede realizar transformaciones de orden de bytes y mover los miembros de la estructura (p. Ej.
uint32_t
O similares) utilizandomemcpy
el búfer. ¿Por quémemcpy
? Debido a que hay muchas plataformas donde no es posible escribir 32 bits (16 bits, 64 bits, sin diferencia) cuando la dirección de destino no está alineada correctamente.Entonces, ya has hecho mucho para lograr la portabilidad.
Y ahora la pregunta final. Tenemos un buffer Los datos se envían a la red TCP / IP. Dicha red asume bytes de 8 bits. La pregunta es: ¿de qué tipo debería ser el búfer? Si tus caracteres son de 9 bits? Si son de 16 bits? 24? ¿Quizás cada carácter corresponde a un byte de 8 bits enviado a la red y solo se utilizan 8 bits? ¿O tal vez múltiples bytes de red están empaquetados en caracteres de 24/16/9 bits? Esa es una pregunta, y es difícil de creer que haya una respuesta única que se ajuste a todos los casos. Muchas cosas dependen de la implementación del socket para la plataforma de destino.
Entonces, de lo que estoy hablando. Por lo general, el código puede hacerse relativamente fácil de transportar hasta cierto punto . Es muy importante hacerlo si espera usar el código en diferentes plataformas. Sin embargo, mejorar la portabilidad más allá de esa medida es algo que requiere mucho esfuerzo y a menudo da poco , ya que el código real casi siempre depende de otro código (implementación de socket en el ejemplo anterior). Estoy seguro de que aproximadamente el 90% de la capacidad del código para trabajar en plataformas con bytes distintos de 8 bits es casi inútil, ya que utiliza un entorno vinculado a 8 bits. Simplemente verifique el tamaño del byte y realice la aserción del tiempo de compilación. Seguramente tendrá que reescribir mucho para una plataforma muy inusual.
Pero si su código es altamente "independiente", ¿por qué no? Puede escribirlo de una manera que permita diferentes tamaños de bytes.
fuente
unsigned char
valor, no debería haber problemas de portabilidad a menos que el código utilice trucos de alias en lugar de cambios para convertir secuencias de octetos a / desde tipos enteros más grandes. Personalmente, creo que el estándar C debería definir intrínsecos para empacar / desempaquetar enteros de secuencias de tipos más cortos (más típicamentechar
) almacenando un número fijo de bits garantizados disponibles por elemento (8 porunsigned char
, 16 porunsigned short
o 32 porunsigned long
).Parece que aún puede comprar un IM6100 (es decir, un PDP-8 en un chip) en un almacén. Esa es una arquitectura de 12 bits.
fuente
Muchos chips DSP tienen 16 o 32 bits
char
. TI hace rutinariamente tales chips, por ejemplo .fuente
Citado de http://en.wikipedia.org/wiki/Byte#History
Sin embargo, no estoy seguro acerca de otros idiomas.
http://en.wikipedia.org/wiki/IBM_7030_Stretch#Data_Formats
Define un byte en esa máquina como longitud variable
fuente
La familia DEC PDP-8 tenía una palabra de 12 bits, aunque generalmente usaba ASCII de 8 bits para la salida (en un teletipo principalmente). Sin embargo, también había un código de caracteres de 6 BIT que le permitía codificar 2 caracteres en una sola palabra de 12 bits.
fuente
Por un lado, los caracteres Unicode son más largos que 8 bits. Como alguien mencionó anteriormente, la especificación C define los tipos de datos por sus tamaños mínimos. Utilice
sizeof
y los valores enlimits.h
si desea interrogar sus tipos de datos y descubrir exactamente qué tamaño son para su configuración y arquitectura.Por esta razón, trato de mantener los tipos de datos como
uint16_t
cuando necesito un tipo de datos de una longitud de bits particular.Editar: Lo siento, inicialmente leí mal tu pregunta.
La especificación C dice que un
char
objeto es "lo suficientemente grande como para almacenar cualquier miembro del conjunto de caracteres de ejecución".limits.h
enumera un tamaño mínimo de 8 bits, pero la definición deja el tamaño máximo de unchar
abierto.Por lo tanto, a
char
es al menos tan largo como el carácter más grande del conjunto de ejecución de su arquitectura (generalmente redondeado al límite de 8 bits más cercano). Si su arquitectura tiene códigos de operación más largos, suchar
tamaño puede ser más largo.Históricamente, el código de operación de la plataforma x86 tenía un byte de largo, así que
char
lo que inicialmente era un valor de 8 bits. Las plataformas x86 actuales admiten códigos de operación de más de un byte, perochar
se mantienen a 8 bits de longitud ya que a eso están condicionados los programadores (y los grandes volúmenes de código x86 existente).Cuando piense en el soporte multiplataforma, aproveche los tipos definidos en
stdint.h
. Si usa (por ejemplo) un uint16_t, puede estar seguro de que este valor es un valor de 16 bits sin signo en cualquier arquitectura, ya sea que ese valor de 16 bits corresponda a achar
,short
,int
, o alguna otra cosa. La mayoría del trabajo duro ya lo han hecho las personas que escribieron su compilador / bibliotecas estándar.Si necesita saber el tamaño exacto de a
char
porque está haciendo una manipulación de hardware de bajo nivel que lo requiere, normalmente utilizo un tipo de datos que es lo suficientemente grande como para contener unchar
en todas las plataformas compatibles (generalmente 16 bits es suficiente) y ejecutar el valor a través de unaconvert_to_machine_char
rutina cuando necesito la representación exacta de la máquina. De esa manera, el código específico de la plataforma se limita a la función de interfaz y la mayoría de las veces puedo usar un normaluint16_t
.fuente
los números mágicos ocurren, por ejemplo, cuando se cambia;
la mayoría de estos pueden manejarse simplemente usando CHAR_BIT y, por ejemplo, UCHAR_MAX en lugar de 8 y 255 (o similar).
espero que su implementación los defina :)
esos son los problemas "comunes" .....
Otro problema indirecto es decir que tiene:
esto podría "solo" tomar (el mejor de los casos) 24 bits en una plataforma, pero podría tomar, por ejemplo, 72 bits en otro lugar .....
si cada uchar contenía "indicadores de bit" y cada uchar solo tenía 2 bits o indicadores "significativos" que estaba usando actualmente, y solo los organizó en 3 uchars para "claridad", entonces podría ser relativamente "más derrochador", por ejemplo, en una plataforma con uchars de 24 bits .....
nada que los campos de bits no puedan resolver, pero tienen otras cosas a tener en cuenta ...
en este caso, una sola enumeración podría ser una forma de obtener el número entero "más pequeño" que realmente necesita ...
tal vez no sea un ejemplo real, pero cosas como esta me "mordieron" al portar / jugar con algún código .....
solo el hecho de que si un uchar es tres veces más grande de lo que se espera "normalmente", 100 de tales estructuras podrían desperdiciar mucha memoria en algunas plataformas ... donde "normalmente" no es un gran problema ... .
así que las cosas todavía pueden estar "rotas" o en este caso "desperdiciar mucha memoria muy rápidamente" debido a la suposición de que un uchar es "no muy derrochador" en una plataforma, en relación con la RAM disponible, que en otra plataforma ... ..
el problema puede ser más prominente, por ejemplo, para ints también, u otros tipos, por ejemplo, tiene una estructura que necesita 15 bits, por lo que la pega en un int, pero en alguna otra plataforma un int es de 48 bits o lo que sea ... .
"normalmente" puede dividirlo en 2 uchars, pero, por ejemplo, con un uchar de 24 bits solo necesitaría uno .....
entonces una enumeración podría ser una mejor solución "genérica" ...
depende de cómo estás accediendo a esos bits aunque :)
por lo tanto, puede haber "fallas de diseño" que críen su cabeza ... incluso si el código aún funciona / funciona bien, independientemente del tamaño de un uchar o uint ...
hay cosas como estas a tener en cuenta, aunque no haya "números mágicos" en su código ...
Espero que esto tenga sentido :)
fuente
enum
es probable que sea más pequeño que otros tipos nativos? ¿Sabe que el valor predeterminado es el mismo almacenamiento queint
? "usted tiene algún tipo de estructura que necesita 15 bits, por lo que se pega en un int, sino en alguna otra plataforma de un int es de 48 bits o lo que sea ....." - así#include <cstdint>
y lo convierten en unaint16_t
de las mejores posibilidades de minimizar el uso de bits . Realmente no estoy seguro de lo que pensaste que estabas diciendo entre todas esas elipses.las entradas solían ser de 16 bits (pdp11, etc.). Ir a arquitecturas de 32 bits fue difícil. La gente está mejorando: casi nadie supone que un puntero cabe en mucho tiempo (¿no es cierto?). O compensaciones de archivos, o marcas de tiempo, o ...
Los caracteres de 8 bits ya son algo anacrónicos. Ya necesitamos 32 bits para contener todos los juegos de caracteres del mundo.
fuente
char
es un poco pintoresco ahora en días Unicode. Me interesan más las unidades de 8 bits (octetos) cuando se trata de datos binarios, por ejemplo, almacenamiento de archivos, comunicaciones de red.uint8_t
Es más útil.