Incohérences sur le resultat de la fonction length [Résolu]

Messages postés
1649
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
- - Dernière réponse : jlen100
Messages postés
1649
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
- 2 avril 2009 à 14:31
bonjour,
je viens de découvrir une incohérence dans le résultat renvoyé par le fonction length()
si l'on prend un type:
  TEntete=
  record
     Nom:String[50];
     Color:char;
     Validite:boolean;
     dateValidite:Tdatetime;
     nul:string[2];
  end;
var Entete:TEntete;
si l'on fait la somme de toute les longueurs on obtient 64
si l'on fait length(Entete) on obtient 72
Etrange Non???
la différence vient de la variable dateValidite qui a une longueur de 8 octets mais est comptée pour 16 octets dans le calcul.
pour s'en convaincre si l'on fait:
  TEnteteBadge =
  record
  Nom:String[50];
  Color:char;
  Validite:boolean;
   nul:string[10];
  end;
la fonction length renvoie bien 64
ceci est assez gênant quand on emploie cette fonction pour extraire la variable d'un TMemoryStream.
Quelqu'un aurait-il une explication?

@jlen
Afficher la suite 

7 réponses

Meilleure réponse
Messages postés
991
Date d'inscription
samedi 25 octobre 2003
Statut
Membre
Dernière intervention
29 août 2013
5
3
Merci
le probleme doit etre du a l'alignement des données. Si tu utilise un "packed record", le resultat devrait etre correcte

Dire « Merci » 3

Quelques mots de remerciements seront grandement appréciés. Ajouter un commentaire

Codes Sources 6035 internautes nous ont dit merci ce mois-ci

Commenter la réponse de Guillemouze
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
Length => string et array
pour tout autres choses : SizeOf !

MemoryStream.Read(Entete, SizeOf(TEntete);

<hr size="2" width="100%" />
Commenter la réponse de f0xi
Messages postés
1649
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
7
0
Merci
excuse moi foxi mais le résultat  est aussi incohérent pour le sizeof !!
Commenter la réponse de jlen100
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

type
  { 50 bytes :
    [50 chars]
  }
  TEnteteName = array[0..49] of char;
  pEnteteName = ^TEnteteName;

const
  EnteteNameSize = SizeOf(TEnteteName);

function StringToEnteteName(const S: string): TEnteteName;
var N, L: integer;
begin
  L := Length(S)-1;
  if L > 49 then
    L := 49;
  for N := 0 to 49 do
    if N <= L then
      result[N] := S[N+1]
    else
      result[N] := #0;
end;

function EnteteNameToString(const E: TEnteteName): String;
var N : integer;
    pR: PChar;
begin
  SetLength(result, 50);
  pR := PChar(result);
  for N := 0 to 49 do
  begin
    pR[N] := E[N];
  end;
end;

type
  { 6 bytes :
    [2 Year][2 Month][2 Day]
  }
  TEnteteDate = record
    Year, Month, Day: word;
  end;
  pEnteteDate = ^TEnteteDate;

const
  EnteteDateSize = SizeOf(TEnteteDate);

function TEnteteDateToDateTime(const eDate: TEnteteDate): TDateTime;
begin
  result := EncodeDate(eDate.Year, eDate.Month, eDate.Day);
end;

function DateTimeToEnteteDate(const aDate: TDateTime): TEnteteDate;
begin
  DecodeDate(aDate, Result.Year, Result.Month, Result.Day);
end;

type
  { 60 bytes :
    [50 Name chars]
    [1 color]
    [1 Validity]
    [2 DateValidity Year][2 DateValidity Month][2 DateValidity Day]
    [2 nul]
  }
  TEntete = record
    Name         : TEnteteName;
    Color        : byte;
    Validity     : boolean;
    DateValidity : TEnteteDate;
    Nul          : word;
  end;
  pEntete = ^TEntete;

const
  EnteteSize = SizeOf(TEntete);

procedure TForm1.FormCreate(Sender: TObject);
begin
  caption := format('%d // %d // %d',[EnteteSize, EnteteNameSize, EnteteDateSize]);
end;

end.

<hr size="2" width="100%" />
Commenter la réponse de f0xi
Messages postés
1649
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
7
0
Merci
foxi,
Il te manque 4 octets et TEnteteDate n'est pas compatible avec un TDateTime 
(il y a plus simple  pour récupérer l'entête 
Var EnteteSize:Integer;
 const EnteteSize:=SizeOf(TEntete.Name)+1+1+SizeOf(TEntete.DateValidity)+SizeOf(TEntete.Nul);
 MemoryStream.Read(Entete, EnteteSize);
on écrit et on lit bien les bonnes variables.
mais cela n'explique pas pourquoi DELPHI se plante dans la conversion du DateValidity. lorsque il est dans un record
chez moi 51+1+1+8+3= 64 pas 72!
Commenter la réponse de jlen100
Messages postés
4200
Date d'inscription
samedi 16 octobre 2004
Statut
Modérateur
Dernière intervention
2 janvier 2019
26
0
Merci
y'a en fait 3 probleme sur ta premiere entete :

String[N] est toujours egal a N+1 (1 pour la taille de la chaine)

soit String[50] + String[2] = 51+3 = 54

ensuite pour TDateTime autre soucis, est censé etre Float 64bits (8 octets) mais se trouve stocké sur 16 octets!
soit un float 128bits !
incomprehensible. d'ou viennent les 8 octets suplementaire ?!

donc si on reprend :

  TEntete=
  record
     Nom:String[50];
     Color:char;
     Validite:boolean;
     dateValidite:Tdatetime;
     nul:string[2];
  end;

50 + 1 + 1 + 8 + 2 = 62 dans la theorie

51 + 1 + 1 + 16 + 3 = 72 dans la pratique 

SizeOf ne renvois donc pas une valeur erronée...

Mon type TEnteteDate est parfaitement compatible avec un TDateTime, mais pour cela il faut utiliser les methodes EncodeDate et DecodeDate pour la lire ... un moyen un peu contraignant de contourner le probleme de taille de TDateTime.
on pourrai pousser plus loin en declarant :

TEnteteDate = record
  Y, M, D, H, N, S, Z : word;
end;

mais cette fois, notre type ferait 14 octets et devras s'utiliser avec les methodes EncodeDateTime et DecodeDateTime.

<hr size="2" width="100%" />
Commenter la réponse de f0xi
Messages postés
1649
Date d'inscription
samedi 10 juillet 2004
Statut
Membre
Dernière intervention
25 juillet 2014
7
0
Merci
merci foxi , merci guillemouze.

effectivement cela fonctionne avec packed record

Cela n'était pas un véritable problème de fonctionnement puisque j'avais trouvé une solution à "l'arrache" mais cela me turlupinait et je n'aime pas ne pas comprendre le pourquoi de la chose.
en fait la variable NUL n'est là que pour ajuster la longueur les données qui suivent sont d'un autre type qui lui fait 64 octets. J'aurais pu effectivement mettre la longueur à 61 ou 72 mais l'ajustement me simplifie les calculs de déplacement dans le stream.... on est toujours un peu flemmard des neurones et du clavier.

enfin encore merci à tous les deux.

Jlen.
Commenter la réponse de jlen100