Dereferencing variabel størrelse Arrays i Structs

stemmer
2

Structs virke som en nyttig måte for å analysere en binær klump av data (dvs. en fil eller en nettpakke). Dette er fint og dandy før du har variabel størrelse arrays i blob. For eksempel:

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

Dette tillater meg å finne den siste data karakter:

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

Problemet er, jeg vil ha flere med variabel lengde matriser:

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

Jeg er ikke manuelt tildele disse strukturene. Jeg har en fil som så:

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

Som jeg prøver å analysere en binærfil (mer spesifikt en klasse fil). Jeg har skrevet en implementering i Java (som var min klasse oppdrag), ingen jeg gjør en personlig versjon i C ++, og håper å komme unna uten å måtte skrive 100 linjer med kode. Noen ideer?

Takk, Stefan

Publisert på 07/10/2008 klokken 14:56
kilden bruker
På andre språk...                            


6 svar

stemmer
3

Dette er en svært farlig konstruksjon, og jeg vil fraråde det. Du kan bare inneholde en variabel lengde array i en struct når det er det siste elementet, og når du gjør det, må du sørge for at du tildele nok minne, for eksempel:

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

Hva du ønsker å gjøre er å bare bruke vanlige dynamisk tildelte matriser:

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;
}
Svarte 07/10/2008 kl. 15:06
kilden bruker

stemmer
3

Du kan ikke ha flere variable størrelse arrays. Hvordan skal kompilatoren ved kompilering vet hvor venn [] ligger? Plasseringen av venn avhenger av størrelsen på data [] og størrelsen på data er ukjent ved kompilering.

Svarte 07/10/2008 kl. 15:02
kilden bruker

stemmer
1

Svarene så langt er alvorlig over-komplisere et enkelt problem. Mecki er rett om hvorfor det ikke kan gjøres på den måten du prøver å gjøre det, men du kan gjøre det svært likt:

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];
Svarte 09/10/2008 kl. 07:31
kilden bruker

stemmer
1

Du kan ikke - i hvert fall ikke på den enkle måten at du forsøker. Den unsized rekke på slutten av en struktur er i utgangspunktet en forskyvning til slutten av strukturen, uten innebygd måte å finne slutten.

Alle feltene er konvertert til numeriske forskyvninger på kompilering, så de trenger å være beregne på den tiden.

Svarte 07/10/2008 kl. 15:05
kilden bruker

stemmer
0

For hva du gjør må du en koder / dekoder for formatet. Dekoderen tar rådata og fyller ut strukturen (i ditt tilfelle tildeling plass for kopien av hver del av dataene), og dekoderen skriver rå binære.

Svarte 07/10/2008 kl. 15:21
kilden bruker

stemmer
-1

(Var 'Bruk std :: vector')

Redigere:

Om du leser tilbakemeldinger, jeg antar at jeg bør utvide mitt svar. Du kan effektivt passe to variabel lengde arrays i strukturen som følger, og lagring vil bli frigjort for deg automatisk når file_data går ut av omfang:

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

nodeheader file_data;

Nå file_data.data.size (), gir etc du lengden og og og file_data.data [0] gir en rå peker til dataene hvis du trenger det.

Du må fylle fildata fra filen stykkevis - les lengden på hver buffer, ring endre størrelse () på reisemålet vektor, så les i dataene. (Det finnes måter å gjøre dette litt mer effektivt. I sammenheng med disk fil I / O, jeg antar det spiller ingen rolle).

Forresten OP teknikk er feil selv for hans 'fint og dandy' tilfeller, for eksempel med bare en VLA på slutten.

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

Det er ingen garanti for at file_data er riktig justert for nodeheader type. Foretrekke for å oppnå file_data av malloc () - som garanterer for å returnere en peker innrettet for en hvilken som helst type - eller ellers (bedre) erklære bufferen for å være av riktig type i første omgang:

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

biggestnodeheader file_data;
// etc...
Svarte 07/10/2008 kl. 15:08
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more