Einzelnen Beitrag anzeigen

Benutzerbild von nicodex
nicodex

Registriert seit: 2. Jan 2008
Ort: Darmstadt
286 Beiträge
 
Delphi 2007 Professional
 
#7

Re: Record Größe zur Laufzeit bestimmen

  Alt 21. Apr 2008, 08:46
Ein wenig Pseudo-Code:
Delphi-Quellcode:
{$ALIGN Alignment}
type
  TFoo = record
    b : Byte; // $00
  //x1: array [0..6] of Byte; // $01 Align(Min(Alignment, SizeOf(a)))
    a : Extended; // $08
  //x2: array [0..1] of Byte; // $12 Align(Min(Alignment, SizeOf(i)))
    i : Integer; // $14
  //x3: array [ ] of Byte // $18 Align(Min(Alignment, SizeOf(MaxMember))
  end; // ($18)
Noch ein Edit um Missverständnissen vorzubeugen
SizeOf(...) in den Kommentaren ist das 'Alignment, welches für das Strukturmitglied benötigt wird'. SizeOf() ist insofern 'inkorrekt', da das Alignment eines strukturierten Typs das Alignment des 'größten Mitglieds' ist.
Beispiel:Arr: array [0..1] of Word; Die benötigte Ausrichtung für Arr ist die Größe eines Elements - nicht SizeOf(Arr)!
Delphi-Quellcode:
Bar: record
  A: Word; // 'größte erforderliche Ausrichtung' in Bar
  B: Byte;
//x: Byte;
end;
SizeOf(Bar) ist 4. Die Ausrichtung für Bar selbst ist 2 (Bar.A erfordert eine Ausrichtung der Struktur an 2 Bytes).

Lösungsansatz für o.g. Problem:
Delphi-Quellcode:
type
  PXType = ^TXType;
  TXType = (
    xByte,
    xWord,
    xInteger,
    xDouble,
    xExtended
  );

const
  XTypeSize: array [TXType] of Cardinal = (
    SizeOf(Byte), // xByte
    SizeOf(Word), // xWord
    SizeOf(Integer), // xInteger
    SizeOf(Double), // xDouble
    SizeOf(Extended) // xExtended
  );

type
  // Dummy type to automatically detect the default alignment
  TAlignmentDetection = record
    A: Byte;
    B: Int64;
  end;

function GetRecordAlignment(const ATypes: array of TXType; AAlignment: Cardinal
  ): Cardinal;
var
  Index: Integer;
  Align: Cardinal;
begin
  if AAlignment < 1 then
    AAlignment := SizeOf(TAlignmentDetection) - SizeOf(Int64);
  Result := 0;
  for Index := Low(ATypes) to High(ATypes) do
  begin
    Align := XTypeSize[ATypes[Index]];
    if Align > AAlignment then
      Align := AAlignment;
    if Align > Result then
      Result := Align;
  end;
end;

function GetRecordSize(const ATypes: array of TXType; AAlignment: Cardinal
  ): Cardinal;
var
  ResultAlign: Cardinal;
  Index: Integer;
  XSize: Cardinal;
  Align: Cardinal;
  Spare: Cardinal;
begin
  if AAlignment < 1 then
    AAlignment := SizeOf(TAlignmentDetection) - SizeOf(Int64);
  Result := 0;
  ResultAlign := 0;
  for Index := Low(ATypes) to High(ATypes) do
  begin
    XSize := XTypeSize[ATypes[Index]];
    if XSize > 1 then
    begin
      Align := XSize;
      if Align > AAlignment then
        Align := AAlignment;
      if Align > ResultAlign then
        ResultAlign := Align;
      Spare := Align - (Result mod Align);
      if Spare < Align then
        Inc(Result, Spare);
    end;
    Inc(Result, XSize);
  end;
  if ResultAlign > 1 then
  begin
    Spare := ResultAlign - (Result mod ResultAlign);
    if Spare < ResultAlign then
      Inc(Result, Spare);
  end;
end;
  Mit Zitat antworten Zitat