2010-08-11 4 views
3

Comment un struct dans un fichier puis-je « pack » et « écrire » en utilisant C de sorte que:écriture « emballé » struct à déposer en C

struct a { 
    uint64_t a; 
    char* b; 
    uint16_t c; 
} a; 
a b; 
b.a = 3; 
b.b = "Hello"; 
b.c = 4;

écrites sur le fichier en tant que

00 00 00 00 00 00 00 03 48 65 6c 6c 6f 00 00 04
+0

Voulez-vous court à stocker en 8 octets ou 4? – Patrick

+0

Pouvez-vous garantir qu'un long et un court sont de la même taille? Ou voulez-vous qu'ils soient écrits et lus comme valeurs de 4 octets quel que soit le type? –

+0

Patrick, "Vulcan Eager", j'ai fait une petite erreur avec l'exemple de sortie. Corrigé cela, ainsi que changé les types de '.a' et' .c' aux types de bits fixes. –

Répondre

9

En C, vous devrez coder une fonction pour le faire pour vous. Vous ne pouvez pas simplement blatir la structure sur le disque car b est un pointeur qui n'a aucun sens sans la chaîne de sauvegarde. Et, à moins que vous sachiez (et pouvez contrôler) comment votre compilateur conditionne ses structures, vous êtes mieux avec une fonction utilitaire de toute façon, même sans pointeurs. Et, comme si cela ne suffisait pas, vous devriez également afficher la longueur de la chaîne afin de connaître le nombre d'octets à lire.

Vous allez chercher quelque chose comme:

int better_than_blat (FILE *f, struct a *x) { 
    size_t len = strlen (x->b); 
    if (fwrite (&(x->a), sizeof(long), 1, f) != 1) return -1; 
    if (fwrite (&len, sizeof(size_t), 1, f) != 1) return -1; 
    if (fwrite (x->b, len, 1, f) != 1) return -1; 
    if (fwrite (&(x->c), sizeof(short), 1, f) != 1) return -1; 
    return 0; 
} 

int better_than_unblat (FILE *f, struct a *x) { 
    size_t len; 
    if (fread (&(x->a), sizeof(long), 1, f) != 1) return -1; 
    if (fread (&len, sizeof(size_t), 1, f) != 1) return -1; 
    x->b = malloc (len + 1); 
    if (x->b == NULL) return -1; 
    memset (x->b, 0, len + 1); 
    if (fread (x->b, len, 1, f) != 1) return -1; 
    if (fread (&(x->c), sizeof(short), 1, f) != 1) return -1; 
    return 0; 
} 
+0

+1 pour utiliser correctement "blat"! –

+0

En outre, l'empaquetage de structure est extrêmement dépendant de la plate-forme/du compilateur, même sans l'apparition d'un pointeur char *, vous aurez besoin de votre propre fonction pour garantir certaines écritures. – KillianDS

2

vous devez écrire votre propre façon de sérialiser ces données; le compilateur ne vous donnera pas un moyen intégré de gérer la chaîne. Il existe des bibliothèques de sérialisation mais je n'en connais pas pour C.

Mais, pensez à utiliser une méthode plus structurée pour sérialiser les données, telles que json ou xml. Même un fichier INI est meilleur qu'un vidage binaire brut. Les raisons sont:

  • plus facile à déboguer
  • plus postcompatible
  • moins rigide/sujette à erreur
  • si vous utilisez une bibliothèque existante, vous récolterez les récompenses de la communauté qui va avec il.
  • une bibliothèque existante est susceptible de prendre en charge les fonctionnalités que vous allez plus tard gratter la tête sur comme des tableaux
  • meilleure compatibilité multi-plateforme.
+2

Arrêtez les overusers XML! – adf88

+0

c'est juste un exemple; Je déteste aussi la surexploitation xml que j'espérais faire allusion à mon commentaire INI. les libs de stockage sont partout, je recommande juste d'en choisir une au lieu d'écrire une corbeille brute. – tenfour

0

Est-ce que l'aide suivante?

struct buffer { 

    char bytes[1000]; 
    int nbytes; 
}; 

struct buffer *new_buffer(){ 
    struct buffer b = (struct buffer*) malloc(sizeof(struct buffer)); 
    b->nbytes = 0; 
    return b; 
} 

void append_long(struct buffer *b, long *l){ 
    memcpy(b->bytes + b->nbytes, l); 
    b->nbytes += sizeof(*l); 
} 

// ...and so on for other types 

void fwrite_buffer(FILE *fp, struct buffer *b){ 
    fwrite(b->bytes, sizeof(*b), 1, fp); 
} 

Utilisation:

struct buffer *buf = new_buffer(); 
struct a b; 
b.a = 3; 
b.b = "Hello"; 
b.c = 4; 
append_long(buf, &(b.a)); 
append_pointer(buf, &(b.b)); 
append_short(buf, &(b.b)); 
fwrite_buffer(fp, buf); 
0

Vous pouvez en toute sécurité emballer la structure en tableau d'octets, si vous n'utiliser des pointeurs dans et définirez explicitement l'alignement d'emballage.

Par exemple (gcc):

 
struct a { 
    long a; 
    char b[256]; 
    short c; 
} __attribute__((__packed__)); 

int size = sizeof(a); 
void* buffer = malloc(size); 
memcpy(buffer, (void*)a, size); 
+0

Cette méthode est extrêmement rapide et vous donnera beaucoup de problèmes à l'avenir. Si vous avez besoin d'une solution simple et maintenable, essayez d'utiliser ProtoBuffers ou MessagePack. Ils sont 10 fois plus lents, mais ce n'est pas un problème à la pratique. – krasnoperov