Einzelnen Beitrag anzeigen

Benutzerbild von Phoenix
Phoenix
(Moderator)

Registriert seit: 25. Jun 2002
Ort: Hausach
7.640 Beiträge
 
#1

Verdrehte Bits (Wilde Pointereien)

  Alt 16. Aug 2007, 19:59
Ich lese (soll lesen) Daten aus einer SPS aus und packe diese in eine Datenbank.

Das klappt einwandfrei. Folgendes steht Testweise in der SPS und dann auch im Blob:
Code:
00 01 00 14 00 1E 00 28 00 32 00 3C 00 00 00 00 00 00 00 00
Nun lese ich den Blob und packe den aus Performancegründen in einen selber allokierten Speicherbereich mit der Länge des Datenbausteins.

Um gezielt auf einzelne Bytes zugreifen zu können, speichere ich den Pointer aus GetMem als PByteArray.
Greife ich nun so auf die Daten zu:
Delphi-Quellcode:
i := 0;

while i < dm.ModuleLength do
begin
  Memo1.Lines.Add('Byte ' + IntToStr(i) + ' : ' + IntToStr(dm.Bytes[i]));
  Inc(i);
end;
Wobei dm mein Datenbaustein (DataModule) ist und dm.Bytes folgendermassen deklariert ist:
Delphi-Quellcode:
FData: PByteArray;
property Bytes[AIndex: Integer]: Byte read GetBytes;
//...
function PLCDataModule.GetBytes(AIndex: Integer): Byte;
begin
  Result := FData^[AIndex];
end;
Bekomme ich folgende Ausgabe:
Code:
Byte 0 : 0
Byte 1 : 1
Byte 2 : 0
Byte 3 : 20
Byte 4 : 0
Byte 5 : 30
Byte 6 : 0
Byte 7 : 40
Byte 8 : 0
Byte 9 : 50
Byte 10 : 0
Byte 11 : 60
Byte 12 : 0
...
Was exakt das ist, was ich erwarte.

Nun zum Problem:

Manche Datenbereiche in der SPS sind größer als ein Byte. In der Regel habe ich es mit 2- oder gar 4 Byte grossen Einträgen zu tun, die ich gegen Bitmasken mit verschiedenen Operatoren (Gleichheit, invertiert verandetet) prüfen muss, um bestimmte Status abzufragen. Diese Bitmasken kann ich also wahlweise als Integer oder als Cardinal speichern. Zur Zeit sind es Integers.

Da die Datenbereiche aber Unregelmässig sind (z.B. 1 Byte, 1 Byte, 6 Byte) kann ich den Pointer nicht auf ein Integer-Array umcasten und den Index (Startbyte) durch 4 Teilen. Das heisst ich muss von einem Pointer auf ein Byte 4 Bytes lesen.

Das mache ich so:
Result := PInteger(Integer(FData) + AIndex)^; Rufe ich das in der gleichen Schleife wie oben alle 4 Bytes, beginnend beim Nullten, auf, bekomme ich folgende Ausgabe:
Code:
Wert 0 : 335544576
Byte 0 : 0
Byte 1 : 1
Byte 2 : 0
Byte 3 : 20
Wert 1 : 671096320
Byte 4 : 0
Byte 5 : 30
Byte 6 : 0
Byte 7 : 40
Wert 2 : 1006645760
Byte 8 : 0
Byte 9 : 50
Byte 10 : 0
Byte 11 : 60
Das ist nicht, was ich erwarte. Denn wenn ich diese Werte in binäre Daten umwandele, dann erhalte ich folgendes:

Code:
Byte 0 - 11 laut der ersten Einzelbyte-Ausgabe:

0  = 00000000 
1  = 00000001
0  = 00000000
20 = 00010100

0  = 00000000
30 = 00011110
0  = 00000000
40 = 00101000

0  = 00000000
50 = 00110010
0  = 00000000
60 = 00111100

Laut dem Windows-Calculator haben diese 3x4 Bytes folgende Werte:

00000000 00000001 00000000 00010100 b =  65556 d
00000000 00011110 00000000 00101000 b = 1966120 d
00000000 00110010 00000000 00111100 b = 3276860 d

Die Werte aus der Ausgabe geben jedoch:

00010100 00000000 00000001 00000000 b = 335544576 d
00101000 00000000 00011110 00000000 b = 671096320 d
00111100 00000000 00110010 00000000 b = 1006645760 d
Warum verdreht die andere Zahlendarstellung auf einmal meine Bytes?
Ich meine, sie stehen ja offenbar auch definitiv andersrum im Speicher.

Nur wenn ich einen Status definiere, der z.B. die ersten 4 Bits prüfen soll, und dann
Code:
11110000 00000000 00000000 00000000 vs.
00000000 00000000 00000000 11110000
verglichen wird, dann gibt das freilich ein False, obwohl ich ein True bräuchte.

Was kann ich da machen?
Sebastian Gingter
Phoenix - 不死鳥, Microsoft MVP, Rettungshundeführer
Über mich: Sebastian Gingter @ Thinktecture Mein Blog: https://gingter.org
  Mit Zitat antworten Zitat