Question

Les structures semblent être un moyen utile d’analyser un blob binaire de données (c’est-à-dire un fichier ou un paquet réseau). C'est parfait jusqu'à ce que vous ayez des tableaux de taille variable dans le blob. Par exemple:

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

Cela me permet de trouver le dernier caractère de données:

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

Le problème, je veux avoir plusieurs tableaux de longueur variable:

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

Je n'alloue pas manuellement ces structures. J'ai un fichier comme celui-ci:

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

Comme j'essaye d'analyser un fichier binaire (plus spécifiquement un fichier de classe). J'ai écrit une implémentation en Java (ce qui était mon devoir de classe), non je fais une version personnelle en C ++ et j'espérais m'en sortir sans avoir à écrire 100 lignes de code. Des idées?

Merci, Stefan

Était-ce utile?

La solution

Vous ne pouvez pas avoir plusieurs tableaux de taille variable. Comment le compilateur au moment de la compilation devrait-il savoir où se trouve friend []? L'emplacement de friend dépend de la taille des données [] et la taille des données est inconnue au moment de la compilation.

Autres conseils

Ceci est une construction très dangereuse, et je le déconseille. Vous ne pouvez inclure un tableau de longueur variable dans une structure que s'il s'agit de l'élément LAST, et vous devez vous assurer que vous allouez suffisamment de mémoire, par exemple:

.

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

Vous voulez simplement utiliser des tableaux classiques alloués dynamiquement:

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

Vous ne pouvez pas, du moins pas de la manière simple que vous essayez. Le tableau non dimensionné à la fin d'une structure est fondamentalement un décalage par rapport à la fin de la structure, sans possibilité de trouver la fin.

Tous les champs sont convertis en décalages numériques lors de la compilation, ils doivent donc pouvoir être calculés à ce moment-là.

Jusqu'à présent, les réponses compliquent sérieusement un problème simple. Mecki a raison de dire que cela ne peut pas être fait comme vous essayez de le faire, mais vous pouvez le faire de la même manière:

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

Pour ce que vous faites, vous avez besoin d’un encodeur / décodeur pour le format. Le décodeur prend les données brutes et remplit votre structure (dans votre cas, en allouant de l'espace pour la copie de chaque section des données), et le décodeur écrit en binaire brut.

(Est-ce que 'Use std :: vector')

Modifier:

Après avoir lu les commentaires, je suppose que je devrais développer ma réponse. Vous pouvez effectivement ajuster deux tableaux de longueur variable dans votre structure comme suit et le stockage sera automatiquement libéré pour vous lorsque fichier_data sortira de sa portée:

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

nodeheader file_data;

Maintenant, file_data.data.size (), etc. vous donne la longueur et & amp; file_data.data [0] vous donne un pointeur brut sur les données si vous en avez besoin.

Vous devrez remplir les données de fichier à partir d'un fichier fragmenté - lisez la longueur de chaque mémoire tampon, appelez resize () sur le vecteur de destination, puis lisez les données. (Il existe des moyens de le faire légèrement plus efficacement. Dans le contexte des E / S sur les fichiers de disque, je suppose que cela n'a pas d'importance.)

Incidemment, la technique de OP est incorrecte, même pour ses affaires "très bien et dandy", par ex. avec un seul VLA à la fin.

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

Rien ne garantit que file_data est correctement aligné pour le type nodeheader. Préférez obtenir file_data par malloc () - ce qui garantit le retour d'un pointeur aligné pour tout type - ou mieux (mieux) déclarez le tampon comme étant du type correct en premier lieu:

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

biggestnodeheader file_data;
// etc...
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top