2010-06-30 4 views
0

J'ai un problème étrange avec la sérialisation d'objet. dans la documentation du fichier, il indique comme suitproblème étrange de sérialisation d'objet dans l'analyse de fichier

Le plomb dans commence par une balise de 4 octets qui identifie un segment TDMS (« TDSM »). Les quatre octets suivants sont utilisés comme masque de bits pour indiquer le type de données que contient le segment . Ce masque de bits est appelé en tant que ToC (Table of Contents). Toute combinaison des drapeaux suivants peuvent être codée dans la table des matières: Les quatre octets contiennent un numéro de version (32 bits entier non signé), qui spécifie la révision de la TDMS un segment le plus ancien est conforme. Au moment de cette écriture , le numéro de version est 4713. La seule version précédente de TDMS a numéro 4712. Les huit octets suivants (entier non signé de 64 bits) décrivent la longueur du segment restant (longueur totale du segment moins longueur de la ligne d'entrée). Si d'autres segments sont ajoutés au fichier , ce numéro peut être utilisé pour localiser le point de départ du segment suivant. Si une application a rencontré un problème grave lors de l'écriture dans un fichier TDMS (accident, panne de courant), tous les octets de cet entier peuvent être 0xFF. Cela peut uniquement arriver au dernier segment dans un fichier. Les huit derniers octets (nombre entier non signé de 64 bits) décrivent la longueur totale des informations méta dans le segment. Cette information est utilisée pour l'accès aléatoire aux données brutes. Si le segment ne contient pas de méta-données du tout (propriétés, informations d'index, objet liste), cette valeur sera 0.

donc je mis en œuvre comme

class TDMsLEADIN { 
public: 
    char Signature[4]; //TDSm 
    __int32  Toc; 
    unsigned __int32  vernum; 
    unsigned __int64 nextSegmentOff; 
    unsigned __int64 rawDataOff; 
}; 
fread(&leadin,sizeof(TDMsLEADIN),1,f); 

alors je suis signature = "TDsm", TOc = 6, vernum = 4712 comme prévu. nextSegmentOff = 833223655424, rawDataOff = 8589934592 mais attendu deux nextSegmentOff et rawDataOff = 194

alors je brise la classe en deux parties, et lu deux deux parties Séparément

class TDMsLEADIN { 
public: 
    char Signature[4]; //TDSm 
    __int32  Toc; 
    unsigned __int32  vernum; 

}; 
class TDMsLeadINend{ 
public: 
    unsigned __int64 nextSegmentOff; 
    unsigned __int64 rawDataOff; 
}; 
    fread(&leadin,sizeof(TDMsLEADIN),1,f); 
    fread(&leadin2,sizeof(TDMsLeadINend),1,f); 

puis je me suis nextSegmentOff, rawDataOff comme attendu = 194. ma question est ce qui ne va pas avec le code original? pourquoi ça marche quand je le casse en deux parties? J'ai essayé non signé long long au lieu de __int64 non signé, mais toujours le même résultat. c'est assez étrange.

Merci

Répondre

1

Vous semblez être en train de lire et écrire les données binaires dans le struct directement.

En général, le compilateur aligner les données de structure pour la performance, donc quand il est un struct il y a un tampon 32 bits caché entre vernum et nextSegmentOff pour aligner nextSegmentOff.Quand il est divisé en deux structures, il n'y a pas de remplissage supplémentaire et vous lisez quatre octets de remplissage et quatre octets de données réelles dans nextSegmentOff.

Vous pouvez le tester en comparant la sizeof(TDMsLEADIN [second version]) + sizeof(TDMsLeadINend)-sizeof(TDMsLEADIN [first version])

La méthode standard pour sérialiser des données est de sérialisation chaque pièce sous-jacente individuellement plutôt que de compter sur la mise en page d'une classe ou structure qui peut changer par le compilateur sans préavis .

+0

Merci vous. cela a un sens parfait. la taille totale est de 32, et la taille de la 1ère partie est de 12 et la 2ème partie de 16. donc il y a une différence de 4 octets. et c'est probablement la partie d'alignement comme vous l'avez dit. merci – Grey

0

Votre problème est que votre compilateur n'a pas compressé la structure de sorte que tous les membres sont les uns à côté des autres. Par exemple, votre compilateur a peut-être bien décidé qu'il aimerait que vos variables 64 bits soient alignées en 64 bits et insère un remplissage de 4 octets dans votre structure pour cela. Si vous avez réellement besoin des performances d'E/S, vous pouvez généralement dire au compilateur d'empaqueter la structure, mais 1) les performances peuvent souffrir lorsque vous utilisez des éléments non alignés dans la structure et 2) votre code. sera nonportable, puisque différents compilateurs le spécifient de différentes manières. Voir Visual C++ equivalent of GCC's __attribute__ ((__packed__)) pour un résumé rapide des façons de le faire sur différents compilateurs.

La façon portable, mais un peu plus prosaïque:

fread(&lead.Signature, 4, 1, f); 
fread(&lead.Toc, sizeof(__int32), 1, f); 
... 
+0

merci. je vais lire le poste pour sûr merci – Grey