Memory-Error :(

Anfängerfragen zum Programmieren mit PureBasic.
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Memory-Error :(

Beitrag von ccode_new »

Code: Alles auswählen

Procedure c_str1(txt.s)
  Protected *c = AllocateMemory(StringByteLength(txt, #PB_UTF8)+1)
  Debug "Memory: " + Str(MemorySize(*c))
  PokeS(*c, txt, -1, #PB_UTF8)
  ProcedureReturn *c
EndProcedure

Procedure c_str2(txt.s)
  Protected *c = AllocateMemory(MemoryStringLength(@txt,#PB_UTF8))
  Debug "Memory: " + Str(MemorySize(*c)) 
  PokeS(*c, txt, -1, #PB_UTF8)
  ProcedureReturn *c
EndProcedure

Procedure c_str3(txt.s)
  Protected *c = AllocateMemory(MemoryStringLength(@txt))
  Debug "Memory: " + Str(MemorySize(*c)) 
  PokeS(*c, txt, -1, #PB_UTF8)
  ProcedureReturn *c
EndProcedure

Debug c_str1("Hallöchen") ;11 Byte (korrekt!)

Debug c_str2("Hallöchen") ;Warum ist der Speicher hier 1 Byte?

Debug c_str3("Hallöchen") ;18 Bytes wären schön, aber falschen Befehl benutzt :(

Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
mk-soft
Beiträge: 3695
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Memory-Error :(

Beitrag von mk-soft »

Code: Alles auswählen

text.s = "0123456789"
a = MemoryStringLength(@text)
b = StringByteLength(text)
Debug "Anzahl Zeichen: "  + a
Debug "Anzahl Bytes: " + b 
... liefert nicht die Byte länge zurück, sondern die Anzahl der Zeichen.

Code: Alles auswählen

MemoryStringLength(@text,#PB_UTF8)
... ist hier falsch, da text von Type Unicode ist.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Memory-Error :(

Beitrag von ccode_new »

Hallo mk-soft,

beide Aussagen von dir sind natürlich korrekt und das ist mir auch vollkommen bekannt,

aber hier: MemoryStringLength(@text,#PB_UTF8)

sollte egal ob es Unicode ist nicht einfach eine völlig sinnlose Zahl zurückgegeben werden.

Hiebei müsste man ja beim Auslesen von Text immer genau wissen ob dies Unicode-Text ist.

Eine eindeutige Fehler-ID-Nummer wäre hier absolut notwendig. (Egal welches Format verarbeitet wird)

Anbei:
Am Ende kommt natürlich die Antwort:
Aus Geschwindigkeitsgründen sollten solche Funktionen nicht zu sicher in der Auswertung sein.
Die Sicherheit ist vom Anwender (Programmierer) sicherzustellen.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Memory-Error :(

Beitrag von STARGÅTE »

ccode_new hat geschrieben: 02.08.2022 03:41 aber hier: MemoryStringLength(@text,#PB_UTF8)

sollte egal ob es Unicode ist nicht einfach eine völlig sinnlose Zahl zurückgegeben werden.

Hiebei müsste man ja beim Auslesen von Text immer genau wissen ob dies Unicode-Text ist.
Die Zahl 1 im zweiten Beispiel ist nicht sinnlos, sondern richtig. Du gibst an, dass der Speicher ist UTF8 codiert ist, übergibst aber einen Speicher mit Unicode-Zechen.
Wenn nun MemoryStringLength() zu lesen beginnt, sieht es im zweiten Byte eine 0 und beendet die Längenmessung und gibt richtigerweise die Länge 1 zurück.
ccode_new hat geschrieben: 02.08.2022 03:41 Eine eindeutige Fehler-ID-Nummer wäre hier absolut notwendig. (Egal welches Format verarbeitet wird)
Was genau ist der Fehler? Woher soll MemoryStringLength() wissen, dass du UTF8 geschrieben hast, aber eigentlich Unicode lesen wolltest.
Anhand des Speichers kann das nicht eindeutig erkannt werden.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Memory-Error :(

Beitrag von ccode_new »

Hi!

So wie die Funktion arbeitet liegt auch kein Fehler vor.
Man könnte sogar mit den Rückgabewert überprüfen ob es Unicode oder nicht ist, da hierbei ja mindestens 2 Byte belegt sein müssten. Aber bei Ascii wird das Ganze dann problematisch.
Bei einem negativen Rückgabewert würde man den Fehler sofort beim Übersetzen merken, wenn -1 Byte im Speicher zugewiesen werden soll und nicht erst zur Laufzeit.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 6996
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Memory-Error :(

Beitrag von STARGÅTE »

ccode_new hat geschrieben: 02.08.2022 12:03 Man könnte sogar mit den Rückgabewert überprüfen ob es Unicode oder nicht ist, da hierbei ja mindestens 2 Byte belegt sein müssten. Aber bei Ascii wird das Ganze dann problematisch.
Bei einem negativen Rückgabewert würde man den Fehler sofort beim Übersetzen merken, wenn -1 Byte im Speicher zugewiesen werden soll und nicht erst zur Laufzeit.
Ich verstehe diese Argumentationskette nicht.

Zur ersten Aussage, was meinst du mit "mindestens 2 Byte belegt sein"? Ein valides Unicode-Zeichen (unter 256) besteht immer aus einem Byte und einem 0-Byte. Es unterscheidet sich somit nicht von einer Ascii- oder UTF8- (bis 127) Zeichenkette mit nur einem Zeichen.
Es gibt keine Funktion, die eindeutig ermitteln kann, ob es sich bei einem Speicherbereich um Ascii, UTF8, Unicode oder sonst was handelt. Die einzige Möglichkeit wäre ein BOM am Anfang des Speicherbereichs zu nutzen oder aber Formate auszuschließen, wenn der Speicher z.B. ungültige Byte-Sequenzen enthält, die in UTF8 oder Unicode keine erlaubten Zeichen darstellen (z.B. die Byte-Werte 192 oder 193 in UTF8).

Bei der zweiten Aussage frage ich mich, in welchem Fall -1 als Wert zurückgegeben werden soll?
  • Mit #PB_Ascii wären alle Byte-Werte valide und es wird immer bis 0 gelesen und dann die Länge zurückgegeben oder halt 1 wenn "aus Versehen" ein Unicode-Codierter String gelesen wird, was die Funktion aber nicht von einem 1-Zeichen langen String unterscheiden kann.
  • Mit #PB_UTF8 gibt es dasselbe Problem, wobei hier -1 zurückgegeben werden könnte, wenn eine Byte-Sequenzen gefunden wird. Das würde dann aber nur in speziellen Fällen funktionieren.
  • Mit #PB_Unicode gibt es sogar das Problem, dass das Zeichenkettenende eines Ascii- oder UFT8-Strings einfach ohne Probleme überlesen werden kann und somit eher zu große Längen zurückgegeben werden.
    Hier sind praktisch alle 2-Byte-Werte möglich und es wird solange gelesen bis zwei 0-Byte auftauchen.
Vielleicht auch noch mal zu den Funktionen selbst:
  • StringByteLength() wird benutzt, um zu bestimmen, wie viele Byte ein String haben würde, wenn man ihn im angegebenen Format speichern wollen würde.
    Also String-to-Memory.
  • MemoryStringLength() wird hingegen benutzt, um zu bestimmen, wie viele Zeichen ein String haben würde, wenn man ihn mit dem angegebenen Format aus einem Speicher lesen würde. Also Memory-to-String
Nach deinem Beispiel zu urteilen, wo du PokeS() verwenden möchtest, wäre also nur StringByteLength() die korrekte Wahl!

Ganz nebenbei: Gerade bei der Datenübertragung wäre es fatal die länge einer Zeichenkette anhand der Zeichen selbst zu bestimmen (also nach dem Ende zu suchen). Übertragungsfehler könnten hier schnell zu unvorhergesehenen Lese-Zyklen führen. Daher wird hier normalerweise entweder gleich auf fixe Längen gesetzt oder aber die Länge vorab geschickt, am besten noch mit einer Prüfsumme versehen.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Memory-Error :(

Beitrag von ccode_new »

Alles Ok!

Deiner Auflistung ist kaum etwas hinzuzufügen.
Die einzige Möglichkeit wäre ein BOM am Anfang des Speicherbereichs zu nutzen
In meinem "speziellen Fall" ist sogar tatsächlich ein "BOM" für UTF8 am Anfang des Speicherbereichs vorhanden.
Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
ccode_new
Beiträge: 1214
Registriert: 27.11.2016 18:13
Wohnort: Erzgebirge

Re: Memory-Error :(

Beitrag von ccode_new »

Ist das hier so korrekt?

Code: Alles auswählen

Procedure fl_utf8decode(*p, *pEnd, *len)
  Protected.a c = PeekA(*p)
  
  If (c < $80)
    If (*len) 
      PokeI(*len, 1)
    EndIf
    ProcedureReturn c
  ElseIf (c < $c2)
    Goto FAIL
  EndIf
  If (*pEnd And *p + 1 >= *pEnd) Or ((PeekA(*p + 1) & $c0) <> $80) 
    Goto FAIL
  EndIf
  If (c < $e0)
    If (*len)
      PokeI(*len, 2)
    EndIf
    ProcedureReturn ((PeekA(*p) & $1f) << 6) + (PeekA(*p + 1) & $3f)
  ElseIf(c = $e0)
    If (PeekA(*p + 1) < $a0) 
      Goto FAIL
    EndIf
    Goto UTF8_3
  ElseIf(c < $f0)
    UTF8_3:
    If (*pEnd And *p + 2 >= *pEnd) Or ((PeekA(*p + 2) & $c0) <> $80) 
      Goto FAIL
    EndIf
    If (*len) 
      PokeI(*len, 3)
    EndIf
    ProcedureReturn ((PeekA(*p) & $0f) << 12) + ((PeekA(*p + 1) & $3f) << 6) + (PeekA(*p + 2) & $3f)
  ElseIf(c = $f0)
    If(PeekB(*p + 1)  < $90) 
      Goto FAIL
    EndIf
    Goto UTF8_4
  ElseIf(c < $f4)
    UTF8_4:
    If (*pEnd And *p + 3 >= *pEnd) Or ((PeekA(*p + 2) & $c0) <> $80) Or ((PeekA(*p + 3) & $c0) <> $80) 
      Goto FAIL
    EndIf
    If (*len)
      PokeI(*len, 4)
    EndIf
    ProcedureReturn ((PeekA(*p) & $07) << 18) + ((PeekA(*p + 1) & $3f) << 12) + ((PeekA(*p + 2) & $3f) << 6) + (PeekA(*p + 3) & $3f)
  ElseIf (c = $f4)
    If (PeekA(*p + 1) > $8f) 
      Goto FAIL; /* after 0x10ffff */
    EndIf
    Goto UTF8_4                                     ;
  Else
    FAIL:
    If (*len) 
      PokeI(*len, 1)
    EndIf
  EndIf
EndProcedure

Procedure fl_utf8test(*src, srclen.i)
  Protected.i ret = 1
  Protected *p = *src
  Protected *e = *src + srclen
  Protected.i len

  While (*p < *e)
    If(PeekA(*p) & $80) ;Das gefundene Zeichen ist größer oder gleich 128
      fl_utf8decode(*p, *e, @len)
      If (len < 2) 
        ProcedureReturn 0
      EndIf
      If (len > ret) 
        ret = len
      EndIf
      *p + len
    Else
      *p + 1
    EndIf
  Wend
  ProcedureReturn ret
EndProcedure

Debug fl_utf8test(UTF8("Hallöchen"), Len("Hallöchen"))

; Examines the first srclen bytes in src And returns a verdict on whether it is UTF-8 Or Not.
; 
; Returns 0 If there is any illegal UTF-8 sequences, using the same rules As fl_utf8decode(). Note that some UCS values considered illegal by RFC 3629, such As 0xffff, are considered legal by this.
; Returns 1 If there are only single-byte characters (ie no bytes have the high bit set). This is legal UTF-8, but also indicates plain ASCII. It also returns 1 If srclen is zero.
; Returns 2 If there are only characters less than 0x800.
; Returns 3 If there are only characters less than 0x10000.
; Returns 4 If there are characters in the 0x10000 To 0x10ffff range.
; Because there are many illegal sequences in UTF-8, it is almost impossible For a string in another encoding To be confused With UTF-8. This is very useful For transitioning Unix To UTF-8 filenames, you can simply test each filename With this To decide If it is UTF-8 Or in the locale encoding. My hope is that If this is done we will be able To cleanly transition To a locale-less encoding.

Betriebssysteme: div. Windows, Linux, Unix - Systeme

no Keyboard, press any key
no mouse, you need a cat
Benutzeravatar
Sicro
Beiträge: 955
Registriert: 11.08.2005 19:08
Kontaktdaten:

Re: Memory-Error :(

Beitrag von Sicro »

Bild
Warum OpenSource eine Lizenz haben sollte :: PB-CodeArchiv-Rebirth :: Pleasant-Dark (Syntax-Farbschema) :: RegEx-Engine (kompiliert RegExes zu NFA/DFA)
Manjaro Xfce x64 (Hauptsystem) :: Windows 10 Home (VirtualBox) :: Neueste PureBasic-Version
Antworten