c ++: trabajando con bytes

Mi problema es que necesito cargar un archivo binario y trabajar con bits individuales del archivo. Después de eso, necesito guardarlo como bytes, por supuesto.

Mi principal problema es: ¿en qué tipo de datos elegir trabajar: char o long int? ¿Puedo de alguna manera trabajar con caracteres?

preguntado el 09 de marzo de 12 a las 14:03

Por cierto, ¿cuánto tiempo es su archivo? ¿Es realmente necesario pensar ya en la optimización? ¿Y tiene que cambiar bytes individuales o son trozos de bytes de "bits individuales"? -

@Deepak: Usar ints para analizar datos binarios es solo pedir problemas de endianness. -

Depende de las operaciones que quiera hacer, ANDing 8 caracteres es igual a una operación int. (x64) -

Deepak: sizeof(long int) no siempre es lo mismo que sizeof(int). Ciertamente no está en la configuración en la que estoy escribiendo esto. -

@Deepak: cuando es lo mismo, ¿por qué sizefo(long int) != sizeof(int) aquí? -

6 Respuestas

A menos que el rendimiento sea una misión crítica aquí, use lo que haga que su código sea más fácil de entender y mantener.

respondido 09 mar '12, 14:03

Ignore mi respuesta, esta es la regla # 1: Daramarak

+1 Y no reinventes la rueda si es posible, si no tienes que trabajar con un formato de serialización predefinido, no te inventes uno. - KillianDS

De acuerdo, aunque es muy divertido reinventar la rueda. "Mira, el mio es cuadrado" - Daramarak

Es posible que una pregunta aclarada pueda invitar a una recomendación más detallada. Sin embargo, no me queda claro que esto deba ser pensado demasiado a partir de la información disponible. - Steve Townsend

Antes de comenzar a codificar cualquier cosa, asegúrese de entender Endianess, tamaños de letra c++, Y cómo extrañas puede ser que sean.

EL unsigned char es el único tipo que tiene un tamaño fijo (byte natural de la máquina, normalmente 8 bits). Entonces, si diseña para la portabilidad, es una apuesta segura. Pero no es difícil simplemente usar el unsigned int o incluso un long long para acelerar el proceso y utilizar size_of para averiguar cuántos bits está obteniendo en cada lectura, aunque el código se vuelve más complejo de esa manera.

Debe saber que para una verdadera portabilidad, ninguno de los tipos internos de c ++ es fijo. Un carácter sin firmar puede tener 9 bits y el int puede ser tan pequeño como en el rango de 0 a 65535, como se indica en este y este https://www.youtube.com/watch?v=xB-eutXNUMXJtA&feature=youtu.be

Otra alternativa, como sugiere user1200129, es usar el aumentar la biblioteca de enteros para reducir todas estas incertidumbres. Esto es si tiene impulso disponible en su plataforma. Aunque si busca bibliotecas externas, hay muchas bibliotecas de serialización para elegir.

Pero antes que nada, incluso antes de comenzar a optimizar, haga algo simple que funcione. Luego, puede comenzar a crear perfiles cuando comience a experimentar problemas de tiempo.

contestado el 23 de mayo de 17 a las 13:05

Sí, el mundo de la programación se vuelve extraño una vez que comienzas a explorar plataformas alienígenas;) - Daramarak

Puede usar boost integer.hpp para tipos de int portátiles. Por ejemplo, si necesita asegurarse de obtener 64 bits firmados, puede usar boost::int64_t en diferentes compiladores y sistemas operativos y siempre obtendrá el tipo que espera. Esto es especialmente importante cuando necesita reinterpretar_cast datos. - 01100110

Realmente solo depende de lo que quieras hacer, pero diría que, en general, la mejor velocidad será mantener el tamaño de los números enteros en los que está compilado tu programa. Entonces, si tienes un programa de 32 bits, elige 32 enteros de bits, y si tiene 64 bits, elija 64 bits.

Esto podría ser diferente si hay algunos bytes en su archivo o si hay números enteros. Sin conocer la estructura exacta de su archivo, es difícil determinar cuál es el valor óptimo.

respondido 09 mar '12, 14:03

Sus oraciones no son realmente correctas en inglés, pero en la medida en que puedo interpretar la pregunta, puede usar mejor el tipo de carácter sin firmar (que es un byte) para poder modificar cada byte por separado.

Editar: cambiado según el comentario.

respondido 09 mar '12, 14:03

¿Qué es un byte sin firmar? byte es un carácter sin firmar. - MByD

Ahora es un inglés algo correcto. :) - Profesor Falken

Como no existe una definición para byte en C, no puedes decir si está firmado o no. - Señor lister

@Michel, lo editaste al revés. estabas buscando unsigned char. - Señor lister

Fijo (Síndrome de los viernes por la tarde) - michel keijzers

Si está tratando con bytes, la mejor manera de hacerlo es usar un tipo de tamaño específico.

#include <algorithm>
#include <iterator>
#include <cinttypes>
#include <vector>
#include <fstream>

int main()
{
     std::vector<int8_t> file_data;
     std::ifstream file("file_name", std::ios::binary);

     //read
     std::copy(std::istream_iterator<int8_t>(file),
               std::istream_iterator<int8_t>(),
               std::back_inserter(file_data));

     //write
     std::ofstream out("outfile");           
     std::copy(file_data.begin(), file_data.end(),
               std::ostream_iterator<int8_t>(out));

}

EDITAR error solucionado

respondido 09 mar '12, 14:03

No se garantiza que uint8_t esté definido para todos los sistemas. Pero establece mucho más claramente la intención del uso. - Daramarak

El estándar C99 existe desde hace mucho tiempo y casi todos los sistemas tienen <stdint.h>. (Honestamente, no puedo pensar en uno que no lo haga. Es uno de los encabezados más fáciles de proporcionar). El equivalente de C ++ podría no estar allí, pero eso se soluciona fácilmente. - mike de simone

Si necesita hacer cumplir cuántos bits hay en un tipo entero, debe usar el <stdint.h> encabezamiento. Está presente tanto en C como en C++. Define el tipo como uint8_t (entero sin signo de 8 bits), que se garantiza que se resolverán en el tipo adecuado en la plataforma. También les dice a otros programadores que leen su código que la cantidad de bits es importante.

Si le preocupa el rendimiento, es posible que desee utilizar los tipos de más de 8 bits, como uint32_t. Sin embargo, al leer y escribir archivos, deberá prestar atención a la Endianess de su sistema En particular, si tiene un ascendente hacia la izquierda sistema (por ejemplo, x86, la mayoría de ARM), entonces el valor de 32 bits 0x12345678 se escribirá en el archivo como los cuatro bytes 0x78 0x56 0x34 0x12, mientras que si tienes un big endian (por ejemplo, Sparc, PowerPC, Cell, algunos ARM e Internet), se escribirá como 0x12 0x34 0x56 0x78. (igual va o lectura). Por supuesto, puede trabajar con tipos de 8 bits y evitar este problema por completo.

respondido 09 mar '12, 14:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.