Pregunta

Las estructuras parecen ser una forma útil de analizar un blob de datos binarios (es decir, un archivo o un paquete de red). Esto es bueno y elegante hasta que tenga matrices de tamaño variable en el blob. Por ejemplo:

struct nodeheader{
        int flags;
        int data_size;
        char data[];
};

Esto me permite encontrar el último carácter de datos:

nodeheader b;
cout << b.data[b.data_size-1];

Por ser un problema, quiero tener varias matrices de longitud variable:

struct nodeheader{
    int friend_size;
    int data_size;
    char data[];
    char friend[];
};

No estoy asignando manualmente estas estructuras. Tengo un archivo así:

char file_data[1024];
nodeheader* node = &(file_data[10]);

Cuando estoy tratando de analizar un archivo binario (más específicamente un archivo de clase). Escribí una implementación en Java (que era mi asignación de clase), no, estoy haciendo una versión personal en C ++ y esperaba escapar sin tener que escribir 100 líneas de código. ¿Alguna idea?

Gracias, Stefan

¿Fue útil?

Solución

No puede tener múltiples matrices de tamaño variable. ¿Cómo debe saber el compilador en tiempo de compilación dónde se encuentra el amigo []? La ubicación del amigo depende del tamaño de los datos [] y el tamaño de los datos se desconoce en el momento de la compilación.

Otros consejos

Este es un constructo muy peligroso, y aconsejaría no hacerlo. Solo puede incluir una matriz de longitud variable en una estructura cuando es el elemento LAST, y cuando lo hace, debe asegurarse de asignar suficiente memoria, por ejemplo:

nodeheader *nh = (nodeheader *)malloc(sizeof(nodeheader) + max_data_size);

Lo que quieres hacer es utilizar matrices asignadas dinámicamente:

struct nodeheader
{
  char *data;
  size_t data_size;
  char *friend;
  size_t friend_size;
};

nodeheader AllocNodeHeader(size_t data_size, size_t friend_size)
{
  nodeheader nh;
  nh.data = (char *)malloc(data_size);  // check for NULL return
  nh.data_size = data_size;
  nh.friend = (char *)malloc(friend_size);  // check for NULL return
  nh.friend_size = friend_size;

  return nh;
}

void FreeNodeHeader(nodeheader *nh)
{
  free(nh->data);
  nh->data = NULL;
  free(nh->friend);
  nh->friend = NULL;
}

No puedes, al menos no de la manera simple que estás intentando. La matriz sin tamaño al final de una estructura es básicamente un desplazamiento hacia el final de la estructura, sin una forma integrada de encontrar el final.

Todos los campos se convierten en desplazamientos numéricos en tiempo de compilación, por lo que deben ser calculables en ese momento.

Hasta ahora, las respuestas están complicando demasiado un problema simple. Mecki tiene razón en cuanto a por qué no se puede hacer de la manera en que lo intentas, pero puedes hacerlo de manera muy similar:

struct nodeheader
{
    int friend_size;
    int data_size;
};

struct nodefile
{
    nodeheader *header;
    char *data;
    char *friend;
};

char file_data[1024];

// .. file in file_data ..

nodefile file;
file.header = (nodeheader *)&file_data[0];
file.data = (char *)&file.header[1];
file.friend = &file.data[file->header.data_size];

Para lo que está haciendo, necesita un codificador / decodificador para el formato. El decodificador toma los datos sin procesar y completa su estructura (en su caso, asignando espacio para la copia de cada sección de los datos), y el decodificador escribe los archivos en bruto sin formato.

(Fue 'Use std :: vector')

Editar:

Al leer los comentarios, supongo que debería ampliar mi respuesta. Puede ajustar efectivamente dos matrices de longitud variable en su estructura de la siguiente manera, y el almacenamiento se liberará automáticamente cuando file_data se encuentre fuera del alcance:

struct nodeheader {
    std::vector<unsigned char> data;
    std::vector<unsigned char> friend_buf; // 'friend' is a keyword!
    // etc...
};

nodeheader file_data;

Ahora file_data.data.size (), etc. le da la longitud y & amp; file_data.data [0] le da un puntero sin procesar a los datos si lo necesita.

Tendrá que rellenar los datos del archivo por partes: lea la longitud de cada búfer, llame a resize () en el vector de destino y luego lea los datos. (Hay formas de hacer esto de manera un poco más eficiente. En el contexto de la E / S de archivos de disco, supongo que no importa).

Incidentalmente, la técnica de OP es incorrecta incluso para sus casos "finos y elegantes", p. ej. con un solo VLA al final.

char file_data[1024];
nodeheader* node = &(file_data[10]);

No hay garantía de que file_data esté alineado correctamente para el tipo de encabezado de nodo. Prefiere obtener file_data by malloc (), que garantiza devolver un puntero alineado para cualquier tipo, o bien (mejor) declare que el búfer es del tipo correcto en primer lugar:

struct biggestnodeheader {
    int flags;
    int data_size;
    char data[ENOUGH_SPACE_FOR_LARGEST_HEADER_I_EVER_NEED];
};

biggestnodeheader file_data;
// etc...
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top