una que programa para operaciones los hexadecimal hacen ejemplos convertir con como cadena binarios binario archivos c++ c character-encoding bytebuffer rawbytestring

que - C/C++ ¿Por qué usar caracteres sin firmar para datos binarios?



programa para convertir de binario a hexadecimal en c++ (8)

¿Es realmente necesario usar caracteres no firmados para almacenar datos binarios como en algunas bibliotecas que funcionan con codificación de caracteres o búferes binarios?

"¿realmente necesario? No.

Sin embargo, es una muy buena idea y hay muchas razones para esto.

Su ejemplo utiliza printf, que no es seguro para el tipo. Es decir, printf toma sus señales de formato de la cadena de formato y no del tipo de datos. Podrías intentarlo fácilmente:

printf("%s/n", (void*)c);

... y el resultado hubiera sido el mismo. Si intentas lo mismo con c ++ iostreams, el resultado será diferente (dependiendo de la firma de c).

¿Qué razonamiento podría abogar por el uso de caracteres no firmados en lugar de caracteres simples?

Sin firmar especifica que el bit más significativo de los datos (para los caracteres sin signo en el octavo bit) representa el signo. Como obviamente no necesita eso, debe especificar que sus datos no están firmados (el bit "signo" representa datos, no el signo de los otros bits).

¿Es realmente necesario usar caracteres unsigned char para almacenar datos binarios como en algunas bibliotecas que funcionan con codificación de caracteres o búferes binarios? Para entender mi pregunta, eche un vistazo al siguiente código:

char c[5], d[5]; c[0] = 0xF0; c[1] = 0xA4; c[2] = 0xAD; c[3] = 0xA2; c[4] = ''/0''; printf("%s/n", c); memcpy(d, c, 5); printf("%s/n", d);

tanto la salida printf''s 𤭢 correctamente, donde f0 a4 ad a2 es la codificación para el punto de código Unicode U+24B62 (𤭢) en hexadecimal.

Incluso memcpy también copió correctamente los bits retenidos por un char.

¿Qué razonamiento podría abogar por el uso de caracteres unsigned char lugar de caracteres plain char ?

En otras preguntas relacionadas, el unsigned char está resaltado porque es el único tipo de datos (byte / más pequeño) que se garantiza que no tiene relleno por la especificación de C. Pero como se mostró en el ejemplo anterior, la salida no parece verse afectada por ningún relleno como tal.

He utilizado VC ++ Express 2010 y MinGW para compilar lo anterior. Aunque VC dio la advertencia.

warning C4309: ''='' : truncation of constant value

La salida no parece reflejar eso.

PS Esto podría marcarse como un posible duplicado de ¿Debería un buffer de bytes estar firmado o sin signo? pero mi intento es diferente Estoy preguntando por qué algo que parece estar funcionando tan bien con char debería escribirse unsigned char ?

Actualización: Para citar de N3337,

Section 3.9 Types

2 Para cualquier objeto (que no sea un subobjeto de clase base) de tipo T que se pueda copiar de forma trivial, ya sea que el objeto tenga o no un valor válido de tipo T, los bytes subyacentes (1.7) que forman el objeto se pueden copiar en una matriz de caracteres o sin firma char. Si el contenido de la matriz de caracteres char o unsigned se copia nuevamente en el objeto, el objeto mantendrá su valor original.

En vista del hecho anterior y de que mi ejemplo original estaba en la máquina Intel, donde el valor predeterminado es el de char y signed char , todavía no estoy convencido de que se prefiera el unsigned char sobre el de char .

¿Algo más?


Estoy preguntando por qué algo que parece estar funcionando tan bien con char debería escribirse unsigned char?

Si hace cosas que no son "correctas" en el sentido de la norma, confía en un comportamiento indefinido. Tu compilador puede hacerlo de la manera que quieres hoy, pero no sabes qué hará mañana. No sabe qué hace GCC o VC ++ 2012. O incluso si el comportamiento depende de factores externos o compilaciones de Depuración / Liberación, etc. En cuanto abandone la ruta segura del estándar, es posible que tenga problemas.


Bueno, ¿a qué llamas "datos binarios"? Esto es un montón de bits, sin ningún significado asignado por esa parte específica del software que los llama "datos binarios". ¿Cuál es el tipo de datos primitivo más cercano, que transmite la idea de la falta de algún significado específico para cualquiera de estos bits? Creo que unsigned char .


El tipo de caracteres simples es problemático y no debe utilizarse para nada más que cadenas. El principal problema con char es que no puede saber si está firmado o sin firmar: este es un comportamiento definido por la implementación. Esto hace que char sea ​​diferente de int , etc., siempre se garantiza que int está firmado.

Aunque VC dio la advertencia ... truncamiento de valor constante.

Le está diciendo que está intentando almacenar literales int dentro de las variables char. Esto podría estar relacionado con la firmeza: si intenta almacenar un número entero con valor> 0x7F dentro de un carácter firmado, pueden suceder cosas inesperadas. Formalmente, este es un comportamiento indefinido en C, aunque prácticamente obtendríamos una salida extraña si intentas imprimir el resultado como un valor entero almacenado dentro de un carácter (firmado).

En este caso específico, la advertencia no debería importar.

EDITAR:

En otras preguntas relacionadas, el signo sin signo está resaltado porque es el único tipo de datos (byte / más pequeño) que se garantiza que no tiene relleno por la especificación de C.

En teoría, todos los tipos de enteros, excepto los caracteres sin signo y los caracteres con signo, pueden contener "bits de relleno", según C11 6.2.6.2:

"Para los tipos de enteros sin signo distintos de los caracteres sin signo, los bits de la representación del objeto se dividirán en dos grupos: bits de valor y bits de relleno (no es necesario que haya ninguno de estos últimos)".

"Para los tipos de enteros con signo, los bits de la representación del objeto se dividirán en tres grupos: bits de valor, bits de relleno y el bit de signo. No es necesario que haya bits de relleno; el carácter firmado no tendrá ningún bit de relleno".

El estándar C es intencionalmente vago y difuso, permitiendo estos bits de relleno teóricos porque:

  • Permite diferentes tablas de símbolos que las estándar de 8 bits.
  • Permite la firma definida por la implementación y los formatos enteros con signo extraño, como el complemento o "signo y magnitud".
  • Un entero no necesariamente usa todos los bits asignados.

Sin embargo, en el mundo real fuera del estándar C, se aplica lo siguiente:

  • Las tablas de símbolos son casi seguramente de 8 bits (UTF8 o ASCII). Existen algunas excepciones extrañas, pero las implementaciones limpias utilizan el tipo estándar wchar_t cuando se implementan tablas de símbolos de más de 8 bits.
  • La firma es siempre el complemento de dos.
  • Un entero siempre usa todos los bits asignados.

Por lo tanto, no hay una razón real para usar caracteres sin firmar o caracteres con signo solo para esquivar algunos escenarios teóricos en el estándar C.


En C, el tipo de datos unsigned char es el único tipo de datos que tiene las siguientes tres propiedades simultáneamente.

  • no tiene bits de relleno, donde todos los bits de almacenamiento contribuyen al valor de los datos
  • ninguna operación a nivel de bits a partir de un valor de ese tipo, cuando se convierte de nuevo a ese tipo, puede producir un desbordamiento, representaciones de trampa o comportamiento indefinido
  • puede alias otros tipos de datos sin violar las "reglas de aliasing", es decir, el acceso a los mismos datos a través de un puntero que se escribe de manera diferente garantiza que se verán todas las modificaciones

Si estas son las propiedades de un tipo de datos "binario" que está buscando, definitivamente debe usar caracteres unsigned char .

Para la segunda propiedad necesitamos un tipo que unsigned esté unsigned . Para estos, todas las conversiones se definen con el módulo arihmético, aquí el módulo UCHAR_MAX+1 , 256 en la mayoría del 99% de las arquitecturas. Toda conversión de valores más amplios a caracteres unsigned char solo corresponde al truncamiento en el byte menos significativo.

Los otros dos tipos de caracteres generalmente no funcionan de la misma manera. signed char está firmado, de todos modos, por lo que la conversión de valores que no encajan no está bien definida. char no está programado para ser firmado o sin firmar, pero en una plataforma en particular a la que se transfiere su código, puede estar firmado incluso si no está firmado en el suyo.


La firma del tipo de char simple está definida por la implementación, por lo tanto, a menos que esté tratando con datos de caracteres (una cadena que usa el conjunto de caracteres de la plataforma, generalmente ASCII), generalmente es mejor especificar la firma explícitamente ya sea con el signed char o unsigned char .

Para los datos binarios, la mejor opción es, probablemente, el unsigned char , especialmente si las operaciones a nivel de bits se realizarán en los datos (específicamente el desplazamiento de bits, que no se comporta igual para los tipos con signo que para los tipos sin signo).


Los bytes suelen entenderse como enteros sin signo de 8 bits de ancho.

Ahora, char no especifica el signo del entero: en algunos compiladores char podría estar firmado, en otros puede estar sin firmar.

Si agrego una operación de cambio de bit al código que escribiste, entonces tendré un comportamiento indefinido. La comparación añadida también tendrá un resultado inesperado.

char c[5], d[5]; c[0] = 0xF0; c[1] = 0xA4; c[2] = 0xAD; c[3] = 0xA2; c[4] = ''/0''; c[0] >>= 1; // If char is signed, will the 7th bit go to 0 or stay the same? bool isBiggerThan0 = c[0] > 0; // FALSE if char is signed! printf("%s/n", c); memcpy(d, c, 5); printf("%s/n", d);

Con respecto a la advertencia durante la compilación: si el carácter está firmado, entonces está intentando asignar el valor 0xf0, que no puede representarse en el carácter firmado (rango -128 a +127), por lo que se convertirá en un valor firmado (- dieciséis).

Declarar el carácter como firmado eliminará la advertencia, y siempre es bueno tener una versión limpia sin ninguna advertencia.


Obtendrá la mayoría de sus problemas al comparar los contenidos de bytes individuales:

char c[5]; c[0] = 0xff; /*blah blah*/ if (c[0] == 0xff) { printf("good/n"); } else { printf("bad/n"); }

puede imprimir "mal", porque, dependiendo de su compilador, c [0] será signo extendido a -1, que no es lo mismo que 0xff