[gelöst] Frage zu sscanf

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 728
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

[gelöst] Frage zu sscanf

Beitrag von fliegermichl »

Hallo,

wenn ich eine UINT64 Zahl als String repräsentieren möchte, mache ich das so:

Code: Alles auswählen

type
 // RBigIntRec definiert einen Record, welcher den Zugriff auf alle Bestandteile eines 64 Bit Integers erlaubt
 RBigIntRec = record
  case Integer of
   1  : (BigInt   : Int64);   // 1 * 64 Bit
   2  : (LowPart  : Integer;  // 2 * 32 Bit
         HighPart : Integer);
   3  : (LPLW    : word;      // 4 * 16 Bit
         LPHW    : word;
         HPLW    : word;
         HPHW    : word);
   4  : (LPLWLSB : Byte;      // 8 * 8 Bit
         LPLWMSB : Byte;
         LPHWLSB : Byte;
         LPHWMSB : Byte;
         HPLWLSB : Byte;
         HPLWMSB : Byte;
         HPHWLSB : Byte;
         HPHWMSB : Byte);
 end;

function StringToBigInt(s : string) : UInt64;
function BigIntToString(i : UInt64) : string;

implementation

function StringToBigInt(s: string): UInt64;
begin
 with RBigIntRec(Result) do
  sscanf(s, '%d.%d.%d.%d', [@hphw, @hplw, @lphw, @lplw]);
end;

function BigIntToString(i: UInt64): string;
begin
  with RBigIntRec(i) do
    Result := Format('%d.%d.%d.%d', [hphw, hplw, lphw, lplw]);
end;
BigIntToString funktioniert erwartungsgemäß.
StringToBigInt liefert nur Unfug.
Was mache ich da falsch?
Zuletzt geändert von fliegermichl am Mi 13. Jan 2021, 13:55, insgesamt 1-mal geändert.

Benutzeravatar
m.fuchs
Lazarusforum e. V.
Beiträge: 2329
Registriert: Fr 22. Sep 2006, 19:32
OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
CPU-Target: x86, x64, arm
Wohnort: Berlin
Kontaktdaten:

Re: Frage zu sscanf

Beitrag von m.fuchs »

Vergiss SScanf, da wild mit Pointern rumzuschießen führt nur zu Problemen.

Code: Alles auswählen

function StringToBigInt(s: string): UInt64;
var
  Parts: TStringArray;
  r: RBigIntRec;
begin
  Parts := s.Split(['.']);
  r.HPHW := StrToInt(Parts[0]);
  r.HPLW := StrToInt(Parts[1]);
  r.LPHW := StrToInt(Parts[2]);
  r.LPLW := StrToInt(Parts[3]);
  Result := r.BigInt;
end;  
Geht sicher auch noch anders / besser / sicherer /schneller.
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de

Benutzeravatar
Winni
Beiträge: 500
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Frage zu sscanf

Beitrag von Winni »

Hi!

Wenn ich mich recht entsinne solltest Du die Punkte zwischen den Parametern weglassen, also

Code: Alles auswählen

%d%d%d%d
Winni

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 728
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Frage zu sscanf

Beitrag von fliegermichl »

m.fuchs hat geschrieben:
Mi 13. Jan 2021, 11:40
Vergiss SScanf, da wild mit Pointern rumzuschießen führt nur zu Problemen.

Code: Alles auswählen

function StringToBigInt(s: string): UInt64;
var
  Parts: TStringArray;
  r: RBigIntRec;
begin
  Parts := s.Split(['.']);
  r.HPHW := StrToInt(Parts[0]);
  r.HPLW := StrToInt(Parts[1]);
  r.LPHW := StrToInt(Parts[2]);
  r.LPLW := StrToInt(Parts[3]);
  Result := r.BigInt;
end;  
Geht sicher auch noch anders / besser / sicherer /schneller.
Danke das mit dem s.split kannte ich noch gar nicht.
Funktioniert!

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 728
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: Frage zu sscanf

Beitrag von fliegermichl »

Winni hat geschrieben:
Mi 13. Jan 2021, 11:41
Hi!

Wenn ich mich recht entsinne solltest Du die Punkte zwischen den Parametern weglassen, also

Code: Alles auswählen

%d%d%d%d
Winni
Danke für die Info aber funktioniert leider auch nicht.

Warf
Beiträge: 1524
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: MacOS | Win 10 | Linux
CPU-Target: x86_64
Wohnort: Aachen

Re: [gelöst] Frage zu sscanf

Beitrag von Warf »

Das liegt daran das %d einen c "int" typen matcht. Auf den meisten modernen maschinen ein 32 bit wert. Du gibst ihm aber pointer auf words, 16 bit werte. Die 32 bit passen da nicht rein, also wird einfach was dahinter liegt überschrieben. Da sind wahrscheinlich deine anderen variablen, weshalb nur schrott bei rauskommt.
Was du brauchst für words zu lesen ist %hu für "unsigned short int". Aber selbst das muss nicht garantieren das es funktioniert, der C standard sagt das short mindestens 16 bit lang sein muss. Es wäre aber vollkommen valide wenn ein system einen 32 oder 64 bit shorttypen anbietet.

Langer rede kurzer sinn, C ist nervig und du solltest wenn möglich C funktionen vermeiden. Scanf (und auch printf) ist aber in einer eigenen Liga von Schrottigkeit und sollte man wenn möglich nicht mal mit ner Kneifzange anfassen.
Mach das lieber mit split ist einfacher, besser und wahrscheinlich sogar effizienter

Benutzeravatar
Aidex
Beiträge: 13
Registriert: Do 24. Sep 2020, 07:02
OS, Lazarus, FPC: Win10 64bit, Laz v2.0.10
CPU-Target: AMD64

Re: [gelöst] Frage zu sscanf

Beitrag von Aidex »

Es entspricht zwar nicht der Fragestellung, aber wäre es nicht generell besser, eine 64-Bit-Zahl als hexadezimalen String zu repräsentieren?

s:=IntToHex(Int64(x));

x:=UInt64(StrToInt64('$'+s));

Benutzeravatar
fliegermichl
Lazarusforum e. V.
Beiträge: 728
Registriert: Do 9. Jun 2011, 09:42
OS, Lazarus, FPC: Winux (L 2.0.11 FPC 3.2)
CPU-Target: 32/64Bit
Wohnort: Echzell

Re: [gelöst] Frage zu sscanf

Beitrag von fliegermichl »

Aidex hat geschrieben:
Mi 13. Jan 2021, 19:17
Es entspricht zwar nicht der Fragestellung, aber wäre es nicht generell besser, eine 64-Bit-Zahl als hexadezimalen String zu repräsentieren?

s:=IntToHex(Int64(x));

x:=UInt64(StrToInt64('$'+s));
Es geht hier um eine Versionsnummer die als 64 Bit unsigned Int gespeichert wird. 8.1.10.4 z.B.
Das sähe komisch aus als Hexwert.

Wie gesagt, Die Lösung von M.Fuchs funktioniert einwandfrei.

Antworten