Domanda

Le strutture sembrano un modo utile per analizzare un BLOB binario di dati (cioè un file o un pacchetto di rete). Questo va bene e dandy fino a quando non hai matrici di dimensioni variabili nel BLOB. Ad esempio:

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

Questo mi permette di trovare l'ultimo carattere di dati:

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

Problema, voglio avere più array di lunghezza variabile:

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

Non sto allocando manualmente queste strutture. Ho un file così:

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

Mentre sto cercando di analizzare un file binario (più specificamente un file di classe). Ho scritto un'implementazione in Java (che era il mio compito in classe), no, sto facendo una versione personale in C ++ e speravo di scappare senza dover scrivere 100 righe di codice. Qualche idea?

Grazie, Stefan

È stato utile?

Soluzione

Non è possibile avere più matrici di dimensioni variabili. Come dovrebbe il compilatore in fase di compilazione sapere dove si trova friend []? La posizione dell'amico dipende dalla dimensione dei dati [] e la dimensione dei dati è sconosciuta al momento della compilazione.

Altri suggerimenti

Questo è un costrutto molto pericoloso e lo sconsiglio. Puoi includere un array di lunghezza variabile in uno struct quando è l'elemento LAST e quando lo fai, devi assicurarti di allocare memoria sufficiente, ad es .:

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

Quello che vuoi fare è semplicemente usare normali array allocati dinamicamente:

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;
}

Non puoi - almeno non nel modo semplice in cui stai provando. L'array non dimensionato alla fine di una struttura è fondamentalmente un offset rispetto alla fine della struttura, senza alcun modo incorporato per trovare la fine.

Tutti i campi vengono convertiti in offset numerici al momento della compilazione, quindi devono essere calcolabili in quel momento.

Le risposte finora complicano eccessivamente un semplice problema. Mecki ha ragione sul perché non può essere fatto nel modo in cui stai cercando di farlo, tuttavia puoi farlo in modo molto simile:

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];

Per quello che stai facendo hai bisogno di un codificatore / decodificatore per il formato. Il decodificatore prende i dati grezzi e compila la struttura (nel tuo caso allocando spazio per la copia di ogni sezione dei dati), e il decodificatore scrive binari grezzi.

(Was 'Use std :: vector')

Modifica:

Sulla lettura del feedback, suppongo che dovrei espandere la mia risposta. Puoi adattare efficacemente due array di lunghezza variabile nella tua struttura come segue e lo spazio di archiviazione verrà liberato automaticamente quando file_data esce dall'ambito:

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

nodeheader file_data;

Ora file_data.data.size (), ecc. ti dà la lunghezza e e & amp; file_data.data [0] ti dà un puntatore grezzo ai dati se ne hai bisogno.

Dovrai riempire i dati del file dal file frammentario - leggi la lunghezza di ciascun buffer, chiama resize () sul vettore di destinazione, quindi leggi i dati. (Esistono modi per farlo in modo leggermente più efficiente. Nel contesto dell'I / O dei file su disco, suppongo che non abbia importanza).

Per inciso, la tecnica di OP è errata anche per i suoi casi "fini e dandy", ad es. con un solo VLA alla fine.

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

Non vi è alcuna garanzia che file_data sia correttamente allineato per il tipo di nodo. Preferisco ottenere file_data da malloc () - che garantisce di restituire un puntatore allineato per qualsiasi tipo - oppure (meglio) dichiarare innanzitutto che il buffer è del tipo corretto:

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

biggestnodeheader file_data;
// etc...
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top