2009-03-17 4 views

Respuesta

26

En caso de una memoria intermedia de bytes ser firmado carbón o unsigned char o simplemente un char buffer? Cualquier diferencia entre C y C++?

Una pequeña diferencia en cómo la trata la lengua. Una gran diferencia en cómo lo trata la convención.

  • char = ASCII (o UTF-8, pero el signo numérico interpone en el camino allí) Pruebas datos
  • unsigned char = byte
  • signed char = rara vez se utiliza

Y hay código que se basa en en tal distinción. Hace apenas una semana o dos me encontré con un error donde los datos JPEG se corrompían porque se pasaba a la versión char* de nuestra función de codificación Base64 — que "útilmente" reemplazaba todo el UTF-8 no válido en la "cadena". Cambiar a BYTE aka unsigned char fue todo lo que se necesitó para solucionarlo.

+5

¿Por qué los iostreams de C++ usan 'char *' en lugar de 'unsigned char *' para representar los búferes de datos al leer y escribir secuencias binarias a través de los métodos 'read' y' write'? : P – BarbaraKwarc

+1

char firmado no es tan raro. En JNI (interfaz nativa de Java, NDK 14.1), char firmado se define como jbyte. – r0ng

+3

wtf hace java tiene que ver con esto (ugh) – developerbmw

0

Si obtiene un elemento en una variable más amplia, por supuesto tendrá extensión de signo o no.

0

debe y ... tiendo a prefieren sin firmar, ya que se siente más "crudo", menos atractivo para decir "bueno, eso es sólo un montón de pequeñas ints", si quiero hacer hincapié en el binario -idad de los datos.

No creo que alguna vez haya usado un signed char explícito para representar un búfer de bytes.

Por supuesto, una tercera opción es representar el búfer como void * tanto como sea posible. Muchas funciones de E/S comunes funcionan con void *, por lo que a veces la decisión de qué tipo de entero usar se puede encapsular por completo, lo cual es bueno.

+1

El problema es que no se puede usar mucho char sin que se promueva. (char) 0xFF! = (char sin signo) 0xFF. Los bytes son los mismos pero no se comparan iguales. –

4

Es mejor definirlo como char sin signo. De hecho, Win32 tipo BYTE se define como char sin signo. No hay diferencia entre C & C++ entre esto.

+1

Usar un caso particular (Win32) para probar la afirmación general no es la mejor idea. – BarbaraKwarc

0

Hace varios años tuve un problema con una aplicación de consola C++ que imprimía caracteres de color para valores ASCII superiores a 128 y esto se solucionó cambiando de char a carácter no firmado, pero creo que se solucionaba manteniendo el tipo de caracteres también. .

Por ahora, la mayoría de las funciones C/C++ usan caracteres y entiendo ambos idiomas mucho mejor ahora, entonces uso caracteres en la mayoría de los casos.

12

Depende.

Si el búfer está destinado a contener texto, entonces probablemente tenga sentido declararlo como una matriz de char y dejar que la plataforma decida por usted si está firmado o no de manera predeterminada. Eso le dará menos problemas para pasar los datos dentro y fuera de la biblioteca de tiempo de ejecución de la implementación, por ejemplo.

Si el búfer está destinado a contener datos binarios, depende de cómo se vaya a utilizar. Por ejemplo, si los datos binarios son realmente una matriz empaquetada de muestras de datos que tienen medidas de ADC de punto fijo de 8 bits, entonces signed char sería lo mejor.

En la mayoría de los casos del mundo real, el búfer es solo eso, un búfer, y realmente no le importan los tipos de bytes individuales porque llenó el búfer en una operación masiva, y está a punto de aprobar a un analizador para interpretar la compleja estructura de datos y hacer algo útil. En ese caso, declarelo de la manera más simple.

0

¿De verdad te importa? Si no lo hace, simplemente use el valor predeterminado (char) y no ocupe su código con asuntos sin importancia. De lo contrario, los futuros mantenedores se preguntarán por qué usaste firmado (o sin firmar). Haz su vida más simple.

+5

No estoy de acuerdo. Si encuentro una serie de caracteres (firmados), me inclino a pensar que de alguna manera contiene datos textuales. –

+1

De acuerdo con Dave VdE – dcw

+1

¿Y por qué no puede la matriz de caracteres sin signo contener datos de texto? El firmado por defecto de charla simple difiere entre arquitecturas, pero las firmas de libc de funciones de cadena siguen siendo las mismas. –

9

Si en realidad es un búfer de bytes de 8 bits, en lugar de una cadena en la configuración regional predeterminada de la máquina, entonces usaría uint8_t. No es que haya muchas máquinas en las que un carácter no sea un byte (o un byte a octeto), sino que la declaración 'esto es un buffer de octetos' en lugar de 'esto es un string' es a menudo documentación útil.

+0

He pasado por esto, y suena bien en teoría, pero crea muchos problemas si pasa estos datos a las funciones estándar C o POSIX (lectura/escritura de archivos/sockets). –

+4

lectura/escritura POSIX toma un buffer * void *. Las funciones POSIX que esperan un char * (por ejemplo, el argumento de ruta para abrir()) esperan una cadena, no un búfer de bytes. –

3

Para una máxima portabilidad siempre use char sin signo.Hay un par de instancias donde esto podría entrar en juego. Los datos serializados compartidos entre sistemas con diferentes tipos de endian inmediatamente vienen a la mente. Al realizar mayúsculas o minúsculas los valores es otro.

5

que puedes usar ya sea carbón o unsigned char pero nunca firmado carbón. El estándar tiene la siguiente en 3,9/2

Para cualquier objeto (distinto de un subobjeto de la clase base) de tipo POD T, si o no el objeto contiene un valor válido de tipo T, el subyacente bytes (1.7) que componen el objeto puede se copiarán en una matriz de char o unsigned char.If el contenido de la matriz de char o unsigned char se copia de nuevo en el objeto, el objeto deberá mantener posteriormente su valor original.

47

Si desea almacenar datos binarios arbitrarios, debe usar unsigned char. Es el único tipo de datos que garantiza que el estándar C no tiene bits de relleno. Cada otro tipo de datos puede contener bits de relleno en su representación de objeto (que es el que contiene todos los bits de un objeto, en lugar de solo aquellos que determinan un valor). El estado de los bits de relleno no está especificado y no se utilizan para almacenar valores. Por lo tanto, si lee usando char algunos datos binarios, las cosas se reducirán al rango de valores de un carácter (interpretando solo los bits de valor), pero aún puede haber bits que simplemente se ignoran pero aún están allí y leídos por memcpy. Es muy parecido a rellenar bits en objetos reales de estructura. El tipo unsigned char está garantizado para no contener ésos. Así se desprende de 5.2.4.2.1/2 (C99 TC2, n1124 aquí):

Si el valor de un objeto de tipo char es tratado como un entero con signo cuando se utiliza en una expresión , el valor de CHAR_MIN será la misma que la de SCHAR_MIN y el valor de CHAR_MAX será el mismo que el de SCHAR_MAX. De lo contrario, el valor de CHAR_MIN será 0 y el valor de CHAR_MAX será el mismo que el de UCHAR_MAX. El valor será igual UCHAR_MAX2^CHAR_BIT − 1

Desde la última frase se deduce que no hay espacio libre para cualquier bits de relleno. Si usa char como el tipo de su búfer, también tiene el problema de desbordamientos: Asignación de cualquier valor explícitamente a un elemento que está en el rango de 8 bits, por lo que puede esperar que dicha asignación sea correcta, pero no dentro del rango de char, que es CHAR_MIN .. CHAR_MAX, dicha conversión se desborda y causa resultados de implementación definidos, incluido el aumento de las señales.

Incluso si hay algún problema con respecto a lo anterior probablemente no mostrarían en las implementaciones reales (sería una muy mala calidad de aplicación ), que son los mejores para usar el tipo correcto desde el principio en adelante, que es unsigned char.

Para cadenas, sin embargo, el tipo de datos de elección es char, que se entenderá por cadena y funciones de impresión.Usar signed char para estos propósitos me parece una decisión incorrecta.

Para obtener más información, lea this proposal que contiene una solución para una próxima versión del estándar C que eventualmente requerirá que signed char tampoco tenga ningún relleno. Ya está incorporado en el working paper.

+0

B-pero C99 6.2.6.2 dice "el signo firmado no debe tener ningún bit de relleno" – Ivan

+7

Olvídese de C. '[C++ 11: 3.9.1/1]:' [..] _ Un char, un char firmado, y un char sin signo ocupa la misma cantidad de almacenamiento y tiene los mismos requisitos de alineación (3.11); es decir, tienen la misma representación de objeto. Para los tipos de caracteres, todos los bits de la representación del objeto participan en la representación del valor. [...] ¿No sugiere esto que los tres tipos de caracteres tienen, como mínimo, el relleno de _same_? Y lo interpreto que significa que ninguno de ellos tiene ninguno. –

+0

(ver http://stackoverflow.com/a/21176278/560648) –

2

La elección de int8_t vs uint8_t es similar a cuando se compara un ptr a ser NULL.


Desde el punto de vista de la funcionalidad, en comparación con NULL es lo mismo que comparar a 0 porque NULL es un #define para 0.

Pero, personalmente, desde un punto de vista de estilo de codificación, elijo comparar mis punteros a NULL porque el #define NULL connota a la persona que mantiene el código que se está comprobando para un puntero erróneo ...

VS

cuando alguien ve una comparación a 0 connota que son buscando un valor específico.


Por la razón anterior, usaría uint8_t.

-1

Si le miente al compilador, lo castigará.

Si el búfer contiene datos que están de paso, y no los manipulará de ninguna manera, no importa.

Sin embargo, si tiene que operar en el contenido del búfer, la declaración de tipo correcta simplificará su código. No "int val = buf [i] & 0xff;" disparates.

Por lo tanto, piense en qué son realmente los datos y cómo debe usarlos.

0
typedef char byte; 

Ahora usted puede hacer su conjunto sea de byte s. Es obvio para todos lo que quieres decir, y no pierdes ninguna funcionalidad.

Sé que es un poco tonto, pero hace que su código lea 100% como lo desea.

+3

Es ** no ** obvio para los programadores de Windows que están acostumbrados a 'typedef char sin signo BYTE'. – dan04

+0

¿Cómo responde esto la pregunta? –

+3

En su dominio, se refiere a él como "un búfer de bytes". La mayoría de las respuestas hablan de lo que es diferente en las opciones disponibles. Tomé el enfoque de explicar: "Si lo llamas 'byte', es mejor escribirlo de esa manera". 23 personas Upvoted esto como una pregunta interesante, y 12 personas lo HICIERON ESTRELLA - eso es impactante. Aceptaré que mi publicación no intenta responder a la pregunta del usuario, pero también argumentaré que otras respuestas aquí ignoran un aspecto del desarrollo de software que estaba tratando de iluminar: cómo nombrar los tipos de cosas. –

Cuestiones relacionadas