Seite 1 von 1
Memory-Error :(
Verfasst: 01.08.2022 21:59
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 :(
Re: Memory-Error :(
Verfasst: 01.08.2022 22:50
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.
... ist hier falsch, da text von Type Unicode ist.
Re: Memory-Error :(
Verfasst: 02.08.2022 03:41
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.
Re: Memory-Error :(
Verfasst: 02.08.2022 06:57
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.
Re: Memory-Error :(
Verfasst: 02.08.2022 12:03
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.
Re: Memory-Error :(
Verfasst: 02.08.2022 18:59
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.
Re: Memory-Error :(
Verfasst: 02.08.2022 22:00
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.
Re: Memory-Error :(
Verfasst: 04.08.2022 21:18
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.
Re: Memory-Error :(
Verfasst: 04.08.2022 22:37
von Sicro