Char vs unsigned char para matrices de bytes

Cuando se almacenan “matrices de bytes” (blobs …), ¿es mejor utilizar char o unsigned char para los elementos ( unsigned char aka uint8_t )? (El estándar dice que el sizeof de ambos es precisamente 1 byte).

¿Importa en absoluto? ¿O uno es más conveniente o frecuente que el otro? Tal vez, ¿qué bibliotecas como Boost utilizan?

Si char está firmado, la ejecución aritmética en un valor de byte con el bit alto establecido resultará en una extensión de signo cuando se promueva a int ; así por ejemplo:

 char c = '\xf0'; int res = (c << 24) | (c << 16) | (c << 8) | c; 

dará 0xfffffff0 lugar de 0xf0f0f0f0 . Esto puede evitarse ocultando con 0xff .

char puede seguir siendo preferible si estás interactuando con bibliotecas que lo utilizan en lugar de unsigned char .

Tenga en cuenta que una conversión de char * a / from unsigned char * siempre es segura (3.9p2). Una razón filosófica para favorecer el unsigned char es que 3.9p4 en el estándar lo favorece, al menos para representar matrices de bytes que podrían contener representaciones de memoria de objetos:

La representación de objeto de un objeto de tipo T es la secuencia de N objetos de unsigned char tomados por el objeto de tipo T , donde N es igual a sizeof(T) .

Teóricamente, el tamaño de un byte en C ++ depende de la configuración del comstackdor y la plataforma de destino, pero se garantiza que sea de al menos 8 bits, lo que explica por qué se requiere que sizeof(uint8_t) sea ​​1.

Aquí es más precisamente lo que el estándar tiene que decir al respecto

§1.71

La unidad de almacenamiento fundamental en el modelo de memoria C ++ es el byte. Un byte es al menos lo suficientemente grande para contener cualquier miembro del conjunto de caracteres de ejecución básico (2.3) y las unidades de código de ocho bits de la forma de encoding Unicode UTF-8 y está compuesto por una secuencia contigua de bits, cuyo número es Implementación definida. El bit menos significativo se llama el bit de orden inferior; El bit más significativo se llama bit de orden superior. La memoria disponible para un progtwig C ++ consiste en una o más secuencias de bytes contiguos. Cada byte tiene una dirección única.

Por lo tanto, si está trabajando en algún hardware especial donde los bytes no son de 8 bits, puede hacer una diferencia práctica. De lo contrario, diría que es una cuestión de gusto y qué información desea comunicar a través de la elección del tipo.

no hace ninguna diferencia práctica, aunque tal vez desde el punto de vista de la legibilidad es más claro si el tipo unsigned char tiene unsigned char lo que implica valores 0..255.

Uno de los otros problemas con el uso potencial de un valor firmado para blobs es que el valor dependerá de la representación del signo, que no es parte del estándar. Entonces, es más fácil invocar un comportamiento indefinido.

Por ejemplo…

 signed char x = 0x80; int y = 0xffff00ff; y |= (x << 8); // UB 

El valor aritmético real también dependerá estrictamente del complemento de dos, lo que puede dar sorpresas a algunas personas. El uso de unsigned explícitamente evita estos problemas.