Einzelnen Beitrag anzeigen

Benutzerbild von JamesTKirk
JamesTKirk

Registriert seit: 9. Sep 2004
Ort: München
604 Beiträge
 
FreePascal / Lazarus
 
#6

AW: Bitpacked Record

  Alt 4. Sep 2014, 07:32
Hallo zusammen,

hat jemand Erfahrung mit bitpacked record unter FPC ?

[...]

Ist das so korrekt? Ich hab ein kleines Test-programm geschrieben, dort funktioniert das Setzen und Lesen der Bits, aber funktioniert das in Kombination mit der WinAPI/DirectDraw ? Hat da jemand Erfahrung
Ja, das ist so korrekt (BitSizeOf(TDWRITE_LINE_BREAKPOINT) gibt zum Beispiel korrekterweise 8 zurück). Du musst nur aufpassen, da wir keinerlei Garantie für irgendwelche Ausrichtungen in bitpacked Records oder Arrays geben, dass es für dich wirklich korrekt funktioniert (was aktuell zumindest unter i386 jedoch der Fall ist). Außerdem unterstützen solche Typen keine RTTI (sollte in deinem Fall kein Problem sein, aber sicher ist sicher ).
Der WinAPI bzw. DirectDraw ist es dann jedoch egal, ob das Record bitpacked ist oder nicht, da ja das Speicherlayout das gleiche ist. Solang die Daten sich alle innerhalb des einen Bytes befinden, solltest du da keine Probleme erhalten.

Ich hab auch mal nen kleinen Test gemacht als Vergleich zwischen dem Zugriff über bitpacked und über inline Getter/Setter:

Delphi-Quellcode:
program tbitpackedtest;

{$mode objfpc}
{$modeswitch advancedrecords}

{$IFDEF FPC}
type
    Unsigned_Bit2 = 0 .. (1 shl 2) - 1;
{$ENDIF}

type
    TDWRITE_LINE_BREAKPOINT = {$IFDEF FPC} bitpacked {$ENDIF} record
    private
      function GetIsWhitespaceProp: Boolean; inline;
      procedure SetIsWhitespaceProp(aValue: Boolean); inline;
    public
      property IsWhitespaceProp: Boolean read GetIsWhitespaceProp write SetIsWhitespaceProp;
    public
    {$IFDEF FPC}
        case Integer of
        0:(
        breakConditionBefore: Unsigned_Bit2;
        breakConditionAfter: Unsigned_Bit2;
        isWhitespace: boolean;
        isSoftHyphen: boolean;
        padding: Unsigned_Bit2);
        1: (LineBreakpointConditions: UINT8);
    {$ELSE}
        LineBreakpointConditions: UINT8;
    {$ENDIF}
    end;
    DWRITE_LINE_BREAKPOINT = TDWRITE_LINE_BREAKPOINT;
    PDWRITE_LINE_BREAKPOINT = ^TDWRITE_LINE_BREAKPOINT;

function TDWRITE_LINE_BREAKPOINT.GetIsWhitespaceProp: boolean;
begin
  Result := (LineBreakpointConditions and $10) <> 0;
end;

procedure TDWRITE_LINE_BREAKPOINT.SetIsWhitespaceProp(avalue: boolean);
begin
  LineBreakPointConditions := (LineBreakpointConditions and not $10) or (Ord(avalue) shl 4);
end;

var
  b: TDWRITE_LINE_BREAKPOINT;
begin
  Writeln(bitsizeof(TDWRITE_LINE_BREAKPOINT), ' ', sizeof(TDWRITE_LINE_BREAKPOINT));
  b.isWhitespace := True;
  b.isWhitespaceProp := True;
end.
Der generierte Assemblercode ist dabei nahezu identisch:

Code:
# [49] b.isWhitespace := True;
        movzbl U_P$TBITPACKEDTEST_B,%eax
        orl    $16,%eax
        movb   %al,U_P$TBITPACKEDTEST_B
# [50] b.isWhitespaceProp := True;
        movzbl U_P$TBITPACKEDTEST_B,%eax
        andl   $-17,%eax
        orl    $16,%eax
        movb   %al,U_P$TBITPACKEDTEST_B
Wobei du aufpassen musst, da inline mit Record Methoden erst mit 2.7.1 korrekt funktioniert (davor musstest du die Unit mit den inline Methoden immer frisch mitkompilieren, damit das geklappt hat; hab ich erst vor kurzem gefixt ).

Gruß,
Sven
Sven
[Free Pascal Compiler Entwickler]
this post is printed on 100% recycled electrons
  Mit Zitat antworten Zitat