Frage

Ich möchte einen Datensatz in Delphi deklarieren, die das gleiche Layout enthält, wie es in C hat.

Für Interessenten: Dieser Datensatz ist Teil einer Vereinigung in der LDT_ENTRY Rekord Windows-Betriebssystem. (Ich brauche diesen Datensatz in Delphi zu verwenden, weil ich auf einem Xbox-Emulator in Delphi gerade arbeite - siehe Projekt Dxbx auf Source)

.

Wie auch immer, wird der Datensatz in Frage wie folgt definiert:

    struct
    {
        DWORD   BaseMid : 8;
        DWORD   Type : 5;
        DWORD   Dpl : 2;
        DWORD   Pres : 1;
        DWORD   LimitHi : 4;
        DWORD   Sys : 1;
        DWORD   Reserved_0 : 1;
        DWORD   Default_Big : 1;
        DWORD   Granularity : 1;
        DWORD   BaseHi : 8;
    }
    Bits;

Soweit ich weiß, gibt es keine Bit-Felder möglich in Delphi. Ich habe versucht dies:

 Bits = record
      BaseMid: Byte; // 8 bits
      _Type: 0..31; // 5 bits
      Dpl: 0..3; // 2 bits
      Pres: Boolean; // 1 bit
      LimitHi: 0..15; // 4 bits
      Sys: Boolean; // 1 bit
      Reserved_0: Boolean; // 1 bit
      Default_Big: Boolean; // 1 bit
      Granularity: Boolean; // 1 bit
      BaseHi: Byte; // 8 bits
  end;

Aber leider: Es ist Größe 10 Bytes wird, statt den erwarteten 4. Ich würde gerne wissen, wie ich die Platte erklären sollte, so dass ich einen Datensatz mit dem gleichen Layout bekommen, die gleiche Größe und den gleichen Mitgliedern. Vorzugsweise ohne Lasten von Getter / Setter.

TIA.

War es hilfreich?

Lösung

Danke an alle!

auf der Grundlage dieser Information I reduziert dies:

RBits = record
public
  BaseMid: BYTE;
private
  Flags: WORD;
  function GetBits(const aIndex: Integer): Integer;
  procedure SetBits(const aIndex: Integer; const aValue: Integer);
public
  BaseHi: BYTE;
  property _Type: Integer index $0005 read GetBits write SetBits; // 5 bits at offset 0
  property Dpl: Integer index $0502 read GetBits write SetBits; // 2 bits at offset 5
  property Pres: Integer index $0701 read GetBits write SetBits; // 1 bit at offset 7
  property LimitHi: Integer index $0804 read GetBits write SetBits; // 4 bits at offset 8
  property Sys: Integer index $0C01 read GetBits write SetBits; // 1 bit at offset 12
  property Reserved_0: Integer index $0D01 read GetBits write SetBits; // 1 bit at offset 13
  property Default_Big: Integer index $0E01 read GetBits write SetBits; // 1 bit at offset 14
  property Granularity: Integer index $0F01 read GetBits write SetBits; // 1 bit at offset 15
end;

Der Index ist wie folgt kodiert: (BitOffset shl 8) + NrBits. Wobei 1 <= NrBits <= 32 und 0 <= BitOffset <= 31

Jetzt kann ich bekommen und diese Bits wie folgt festgelegt:

{$OPTIMIZATION ON}
{$OVERFLOWCHECKS OFF}
function RBits.GetBits(const aIndex: Integer): Integer;
var
  Offset: Integer;
  NrBits: Integer;
  Mask: Integer;
begin
  NrBits := aIndex and $FF;
  Offset := aIndex shr 8;

  Mask := ((1 shl NrBits) - 1);

  Result := (Flags shr Offset) and Mask;
end;

procedure RBits.SetBits(const aIndex: Integer; const aValue: Integer);
var
  Offset: Integer;
  NrBits: Integer;
  Mask: Integer;
begin
  NrBits := aIndex and $FF;
  Offset := aIndex shr 8;

  Mask := ((1 shl NrBits) - 1);
  Assert(aValue <= Mask);

  Flags := (Flags and (not (Mask shl Offset))) or (aValue shl Offset);
end;

Ziemlich raffiniert, findest du nicht?!?!

PS: Rudy Velthuis enthalten nun eine überarbeitete Version dieser in seinem ausgezeichneten „Pitfalls der Umwandlung von“ -Artikel .

Andere Tipps

Rudys Delphi Corner ist die beste Ressource, die ich kenne in Bezug auf Delphi und C / C ++ Interoperabilität. Sein Pitfalls der Umwandlung ist so ziemlich ein Muss lesen, wenn C / C ++ APIs in Delphi verwenden. Das Kapitel werden Sie am meisten interessieren Aufzeichnungen und Ausrichtung -> Bitfelder , aber ich fordere Sie die ganze Sache von oben nach unten zu lesen, zweimal . Die anderen Artikel sind auf jeden Fall die Zeit Investition wert.

Ok, mein Bit Manipulation ist ein bisschen rostig, so konnte ich die Bytes umgekehrt haben. Aber der folgende Code gibt die allgemeine Idee:

type
  TBits = record
  private
    FBaseMid     : Byte;
    FTypeDplPres :  Byte;
    FLimitHiSysEa: Byte;
    FBaseHi      : Byte;

    function GetType: Byte;
    procedure SetType(const AType: Byte);
    function GetDpl: Byte;
    procedure SetDbl(const ADpl: Byte);
    function GetBit1(const AIndex: Integer): Boolean;
    procedure SetBit1(const AIndex: Integer; const AValue: Boolean);
    function GetLimitHi: Byte;
    procedure SetLimitHi(const AValue: Byte);
    function GetBit2(const AIndex: Integer): Boolean;
    procedure SetBit2(const AIndex: Integer; const AValue: Boolean);

  public
    property BaseMid: Byte read FBaseMid write FBaseMid;
    property &Type: Byte read GetType write SetType; // 0..31
    property Dpl: Byte read GetDpl write SetDbl; // 0..3
    property Pres: Boolean index 128 read GetBit1 write SetBit1; 
    property LimitHi: Byte read GetLimitHi write SetLimitHi; // 0..15

    property Sys: Boolean index 16 read GetBit2 write SetBit2; 
    property Reserved0: Boolean index 32 read GetBit2 write SetBit2; 
    property DefaultBig: Boolean index 64 read GetBit2 write SetBit2; 
    property Granularity: Boolean index 128 read GetBit2 write SetBit2; 
    property BaseHi: Byte read FBaseHi write FBaseHi;
  end;

  function TBits.GetType: Byte;
  begin
    Result := (FTypeDplPres shr 3) and $1F;
  end;

  procedure TBits.SetType(const AType: Byte);
  begin
    FTypeDplPres := (FTypeDplPres and $07) + ((AType and $1F) shr 3);
  end;

  function TBits.GetDpl: Byte;
  begin
    Result := (FTypeDplPres and $06) shr 1;
  end;

  procedure TBits.SetDbl(const ADpl: Byte);
  begin
    FTypeDblPres := (FTypeDblPres and $F9) + ((ADpl and $3) shl 1);
  end;

  function TBits.GetBit1(const AIndex: Integer): Boolean;
  begin
    Result := FTypeDplPres and AIndex = AIndex;
  end;

  procedure TBits.SetBit1(const AIndex: Integer; const AValue: Boolean);
  begin
    if AValue then
      FTypeDblPres := FTypeDblPres or AIndex
    else
      FTypeDblPres := FTypeDblPres and not AIndex;
  end;

  function TBits.GetLimitHi: Byte;
  begin
    Result := (FLimitHiSysEa shr 4) and $0F;
  end;

  procedure TBits.SetLimitHi(const AValue: Byte);
  begin
    FLimitHiSysEa := (FLimitHiSysEa and $0F) + ((AValue and $0F) shr 4);
  end;

  function TBits.GetBit2(const AIndex: Integer): Boolean;
  begin
    Result := FLimitHiSysEa and AIndex = AIndex;
  end;

  procedure TBits.SetBit2(const AIndex: Integer; const AValue: Boolean);
  begin
    if AValue then
      FLimitHiSysEa := FLimitHiSysEa or AIndex
    else
      FLimitHiSysEa := FLimitHiSysEa and not AIndex;
  end;

Nun, müssen Sie im Grunde nach unten mit Bit-Manipulation zum schmutzig machen.

Warum, speziell, brauchen Sie diese Struktur behalten?

Wenn Sie nur zu einem Legacy-Programm zu sprechen, die entweder Gespräche in diesem Dialekt (TCP / IP oder ähnliches) oder speichert die Daten auf diese Weise (Dateien, etc.), dann würde ich eine normale Delphi Struktur eine Karte Bit-Version kompatibel. Mit anderen Worten, würde ich eine normalerweise strukturierte Delphi Struktur im Speicher verwenden und Schreiben von Code, Struktur in kompatibler Weise zu schreiben und zu lesen.

Wenn Sie Speicher sparen müssen, würde ich Getter und Setter machen, die Bits der internen Zahlen oder ähnliches zu manipulieren. Dies wird Auswirkungen auf die Leistung haben, aber nicht viel mehr als das, was die ursprüngliche C-Programm haben würde, ist der einzige Unterschied, dass die Bit-Manipulation durch Compiler Magie in der C-Version hinzugefügt werden würde, während Sie es selbst schreiben müssen.

Wenn Sie nicht viele Datensätze im Speicher haben, und müssen nicht in ein anderes Programm zu sprechen, ich habe eine natürliche Delphi Struktur verwenden würde. Trade-off für eine höhere Leistung wird mehr Speicher verwendet werden.

Aber es hängt alles von Ihren Kriterien aus.

In jedem Fall werden Sie nicht in der Lage sein, die Delphi-Compiler in tun die gleiche Arbeit für Sie als C-Compiler zu sprechen.

PACKED RECORD, durch einen anderen hier vorgeschlagenen tun nicht das, und wurde nie gedacht. Es wird nur die Ausrichtung padding entfernen, um ganze Zahlen auf 32-Bit-Grenzen zu setzen und ähnliche, aber nicht mehr Felder in ein Byte packen.

Beachten Sie, dass ein gemeinsamer Weg, dies zu tun ist durch Delphi SETS, die intern mit Bitfeldern implementieren. Auch hier werden Sie anderen Code als die C-Variante haben.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top