Hallo, liebe Leute,
vor einigen Jahren hatte ich einmal das Problem, Zahlen in Strings zu verwandeln, die Lösung, die mir hier von der Liste nahegelegt wurde, lag in Integer2String.
Nun habe ich das umgekehrte Problem, und bevor ich hier unnötig die Liste in Anspruch nehmen wollte, habe ich mich erst einmal auf die Suche gemacht im Verzeichnis "units".
Dort fand ich in der unit "stringutils.pas" folgende Funktion:
function StrReadInt (const s: String; var i: Integer; var Dest: Integer): Boolean; attribute (ignorable);
Das ist sicher genau das, was ich brauche, aber ich verstehe es offenbar nicht, diese Funktion korrekt aufzurufen.
Versucht habe ich folgendes:
StrReadInt (Leistungs_Zahl [3], Leistung [1]);
Wobei "Leistungs_Zahl [3]" das Element aus einem String-Array ist und "Leistung [1]" das Element aus einem Integer-Array.
Dabei beschwert er sich über zu wenig (3) Argumente.
Ich wollte das String-Element als Integer-Zahl dem 1. Element des Arrays "Leistung" zuweisen.
Bei dem Versuch, ein drittes Argument einzufügen (weil ich nicht weiß, was ich da wo eingeben soll, habe ich einfach als hilflosen Versuch noch ein weiteres "Leistung [1]" eingefügt, siehe unten), meckert er zwar überhaupt nicht mehr, aber die Zuweisung findet offensichtlich auch nicht statt.
StrReadInt (Leistungs_Zahl [3], Leistung [1], Leistung [1]);
Kann mir da bitte jemand einen Tip geben?
Danke und Fröhliche Grüße Roland
Hallo liebe Leute,
Ich schrieb:
Versucht habe ich folgendes:
StrReadInt (Leistungs_Zahl [3], Leistung [1]);
Pardon: Das war natürlich sinnlos (Ist mir peinlich #-), denn es ist überhaupt keine Zuweisung, weil ja die Funktion nur den Wert zurückliefert, den ich haben möchte, um die Zuwweisung vorzunehmen.
Inzwischen habe ich mir die Funktion noch einmal gründlich angesehen. Das einzige, wovon ich wirklich glaube, daß ich es verstanden habe, ist, daß sie als zweites Argument eine Variable erwartet, welche die Länge des zu verwandelnden Strings referenziert.
Es muß also wohl eher irgendwie so heißen:
Var laenge, drei, eins: Integer; ...
laenge := 20; drei := 3; eins := 1; Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], laenge, Leistung [eins]);
Das bringt mich aber auch noch nicht wirklich weiter.
Vielleicht kann mir jja hier jemand helfen. :-)
Fröhliche Grüße Roland
Roland Goretzki schrieb:
Hallo, liebe Leute,
vor einigen Jahren hatte ich einmal das Problem, Zahlen in Strings zu verwandeln, die Lösung, die mir hier von der Liste nahegelegt wurde, lag in Integer2String.
Nun habe ich das umgekehrte Problem, und bevor ich hier unnötig die Liste in Anspruch nehmen wollte, habe ich mich erst einmal auf die Suche gemacht im Verzeichnis "units".
Dort fand ich in der unit "stringutils.pas" folgende Funktion:
function StrReadInt (const s: String; var i: Integer; var Dest: Integer): Boolean; attribute (ignorable);
Das ist sicher genau das, was ich brauche, aber ich verstehe es offenbar nicht, diese Funktion korrekt aufzurufen.
S. die Kommentare weiter oben in der Datei (Zeile 163ff.) -- vielleicht nicht offensichtlich erkennbar, dass die dazu gehören.
Diese Funktionen sind v.a. dazu da, wenn man einen String zerlegen will. Wenn der String komplett eine Zahl enthalten soll, ist vermutlich "Val (String, Ziel, FehlerPosition)" einfacher. FehlerPosition (Typ Integer) enthält anschließend 0 bei korrekter Umwandlung, sonst die Position des ersten Fehlers.
Es gibt auch "ReadStr (String, ...)", das wie "Read[Ln]" funktioniert, nur aus einem String statt von der Eingabe liest. Fehler ergeben dann Laufzeitfehler (können aber mit "{$I-}" und IOResult usw. abgefangen werden).
Frank
Hallo Liste, hallo Frank,
Du schriebst:
Roland Goretzki schrieb:
Dort fand ich in der unit "stringutils.pas" folgende Funktion:
function StrReadInt (const s: String; var i: Integer; var Dest: Integer): Boolean; attribute (ignorable);
Das ist sicher genau das, was ich brauche, aber ich verstehe es offenbar nicht, diese Funktion korrekt aufzurufen.
Vielleicht brauche ich doch eher die Funktion Str2Int aus der Unit gpcutil.pas? Aber auch die verstehe ich nicht korrekt aufzurufen.
S. die Kommentare weiter oben in der Datei (Zeile 163ff.) -- vielleicht nicht offensichtlich erkennbar, dass die dazu gehören.
Habe ich mittlerweile gefunden, hat mir aber nicht geholfen. Standardantwort: incompatible types in assignment
[ ... ] Es gibt auch "ReadStr (String, ...)", das wie "Read[Ln]" funktioniert, nur aus einem String statt von der Eingabe liest.
Ja, das könnte es auch tun, ist für mich sicher leichter aufzurufen.
Fehler ergeben dann Laufzeitfehler (können aber mit "{$I-}" und IOResult usw. abgefangen werden).
Fehler? Falls der String doch noch andere Dinge als Ziffern enthält?
Das "{$I-}" bzw. IOResult verstehe ich nicht.
Erst schon einmal Danke und Fröhliche Grüße Roland
PS: Die Uhr funktioniert einwandfrei. GetMicroSecondTime in Verbindung mit UnixTimeToTimeStamp und FormatTime ist ein bewunderungswürdig mächtiges Werkzeug. :-) Dafür auch noch einmal Danke.
Roland Goretzki schrieb:
Vielleicht brauche ich doch eher die Funktion Str2Int aus der Unit gpcutil.pas? Aber auch die verstehe ich nicht korrekt aufzurufen.
Diese Funktion ruft auch nur "Val" auf. Diese Unit ist eigentlich nur zur Kompatiblität mit einer "Turbo Power"-Bibliothek für BP.
S. die Kommentare weiter oben in der Datei (Zeile 163ff.) -- vielleicht nicht offensichtlich erkennbar, dass die dazu gehören.
Habe ich mittlerweile gefunden, hat mir aber nicht geholfen. Standardantwort: incompatible types in assignment
Wie rufst du sie denn jetzt auf? Hast du das Beispiel in dem Kommentar gesehen?
Fehler ergeben dann Laufzeitfehler (können aber mit "{$I-}" und IOResult usw. abgefangen werden).
Fehler? Falls der String doch noch andere Dinge als Ziffern enthält?
Ja.
Das "{$I-}" bzw. IOResult verstehe ich nicht.
OK, wenn du das noch nicht benutzt hast, sind die anderen Varianten in diesem Fall einfacher.
Frank
Hallo Liste, hallo Frank,
Du schriebst:
S. die Kommentare weiter oben in der Datei (Zeile 163ff.) -- vielleicht nicht offensichtlich erkennbar, dass die dazu gehören.
Habe ich mittlerweile gefunden, hat mir aber nicht geholfen. Standardantwort: incompatible types in assignment
Wie rufst du sie denn jetzt auf?
Wie in meiner zweiten E-Mail (hast du die auch schon gelesen?) zu diesem Thread beschrieben:
Var laenge, drei, eins: Integer; ...
laenge := 20; drei := 3; eins := 1; Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], laenge, Leistung [eins]);
Ich verstehe nämlich nicht genau, was die Funktion tut und welche Variablen ich für die Argumente einsetzen muß.
Hast du das Beispiel in dem Kommentar gesehen?
Ja, Du meinst:
i := 1; if StrReadInt (s, i, Size) and StrReadComma (s, i) and ...
Demnach müßte ich also für das 2. Argument die Variable eins einsetzen:
eins := 1; Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [eins]);
Das erste Argument ist der String, aus dem ich die Zahl haben möchte. Vielleicht ist das 3. Argument der springende Punkt. Mir ist überhaupt nicht klar, weshalb noch ein 3. Argument gebraucht wird, also auch nicht, was da erwartet wird.
Zu Str2Int:
Fehler ergeben dann Laufzeitfehler (können aber mit "{$I-}" und IOResult usw. abgefangen werden).
Fehler? Falls der String doch noch andere Dinge als Ziffern enthält?
Ja.
Tut er eigentlich nicht ...
Das "{$I-}" bzw. IOResult verstehe ich nicht.
OK, wenn du das noch nicht benutzt hast, sind die anderen Varianten in diesem Fall einfacher.
So scheint es. Zwar habe ich in einem kleinen Probe-Programm vorhin problemlos gearbeitet, aber mein großes Programm läuft genau dann nicht mehr, wenn ich die Zeile mit Str2Int einkommentiere, obwohl bei der Übersetzung nichts beanstandet wird (Das ist ja wohl en Laufzeitfehler, oder?).
Bevor ich hier um Rat gefragt habe, hätte ich beinahe den String in eine Datei geschrieben und mit ReadLn wieder eingelesen, was meiner Meinung nach auch eine sichere Möglichkeit ist, aber natürlich umständlich und nicht "elegant".
Oder gibt es dabei auch die Möglichkeit mit dem Laufzeitfehler?
Danke und Fröhliche Grüße Roland
Roland Goretzki schrieb:
Hast du das Beispiel in dem Kommentar gesehen?
Ja, Du meinst:
i := 1; if StrReadInt (s, i, Size) and StrReadComma (s, i) and ...
Demnach müßte ich also für das 2. Argument die Variable eins einsetzen:
eins := 1; Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [eins]);
Das erste Argument ist der String, aus dem ich die Zahl haben möchte. Vielleicht ist das 3. Argument der springende Punkt. Mir ist überhaupt nicht klar, weshalb noch ein 3. Argument gebraucht wird, also auch nicht, was da erwartet wird.
Das 3. Argument ist das Ziel, soweit richtig.
Du wunderst dich vermutlich eher über das 2. Argument. Das ist ein Positionszähler, damit man aus einem String nacheinander mehrere Elemente lesen kann. (Eine Variable mit Wert 1 ist hier richtig, allerdings hat sie nichts mit dem Index vom Leistung zu tun, auch wenn am Anfang beide zufällig gleich 1 sind.)
Oder über den Rückgabewert:
: They return True if successful, False otherwise.
Deshalb klappt die Zuweisung an die Zielvariable nicht.
Falls der String doch noch andere Dinge als Ziffern enthält?
Ja.
Tut er eigentlich nicht ...
Dann kannst du auch einfach "ReadStr" verwenden. Wenn er dann doch etwas anderes enthält, gibt es einen Laufzeitfehler. Je nach Anwendung ist das OK oder nicht ...
So scheint es. Zwar habe ich in einem kleinen Probe-Programm vorhin problemlos gearbeitet, aber mein großes Programm läuft genau dann nicht mehr, wenn ich die Zeile mit Str2Int einkommentiere, obwohl bei der Übersetzung nichts beanstandet wird (Das ist ja wohl en Laufzeitfehler, oder?).
Was heißt, es läuft nicht mehr?
Laufzeitfehler sehen so ähnlich aus:
foo: sign or digit expected (error #552 at 804a0b6)
Wenn es immer noch um das CGI-Programm geht, sieht man im Browser nur einen internen Fehler (500 oder so), wenn das Progrmam vorzeitig abbricht. Die genaue Fehlermeldung findet man ggf. im Server-Logfile.
Bevor ich hier um Rat gefragt habe, hätte ich beinahe den String in eine Datei geschrieben und mit ReadLn wieder eingelesen, was meiner Meinung nach auch eine sichere Möglichkeit ist, aber natürlich umständlich und nicht "elegant".
Nein, nicht sehr elegant. ;-) Aber "ReadStr" macht fast genau das Gleiche (nur eleganter).
Oder gibt es dabei auch die Möglichkeit mit dem Laufzeitfehler?
Natürlich. Alle Dateioperationen können Laufzeitfehler verursachen (aus diversen Gründen).
Das grundsätzliche Problem in allen Fällen ist, dass String->Integer-Umwandlung prinzipiell Fehler verursachen kann (während Integer->String immer geht, vorausgesetzt der String ist groß genug). Deshalb muss man die Fehler entweder abfragen (Rückgabewert und Position von StrReadInt bzw. 3. Argument von "Val") und im Fehlerfall irgendwas machen (oder auch gar nichts, indem man den Wert einfach ignoriert; nur ist das Programm dann nicht so robust) oder lässt einen Laufzeitfehler auftreten ("ReadStr" ohne weitere Maßnahmen).
Frank
Hallo Liste, hallo Frank,
der Fehler lag in der falschen Deklaration einer Variablen, die nicht Integer, sondern LongInt sein mußte:
Ist so etwas auch ein Laufzeitfehler?
Jedenfalls hätte ich ohne den Austausch hier den Fehler wohl kaum finden können: Erst bei dem Versuch, genauer zu beschreiben, was alles vor sich geht und "richtig" sein müßte, fiel er mir dann auch nur "zufällig" auf.
Pascal ist schon eine tolle Sprache, und in den letzten Wochen habe ich für meine Verhältnisse sehr viel dazugelernt.
Das folgende zu lesen ist nicht mehr unbedingt notwendig, ich gebe es nur wieder, weil ich hier "so viel Wind" gemacht habe und falls es jemanden interessiert, wie man bei dem Versuch, in einer E-Mail alles möglichst genau zu beschreiben, den "Knackpunkt" finden kann, und weil es noch einige Ungereimtheiten bezüglich StrReadInt enthält, was ich aber nun (zumindest vorläufig) gar nicht benutze.
Herzlichen Dank und Fröhliche Grüße Roland
Du schriebst:
Demnach müßte ich also für das 2. Argument die Variable eins einsetzen:
eins := 1; Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [eins]);
Das erste Argument ist der String, aus dem ich die Zahl haben möchte. Vielleicht ist das 3. Argument der springende Punkt. Mir ist überhaupt nicht klar, weshalb noch ein 3. Argument gebraucht wird, also auch nicht, was da erwartet wird.
Das 3. Argument ist das Ziel, soweit richtig.
Das heißt, daß dort genau dasselbe stehen muß wie das, dem ich es zuweisen möchte? Klingt merkwürdig, habe ich aber im obigen Beispiel probiert, weil mir nichts Besseres einfiel.
Du wunderst dich vermutlich eher über das 2. Argument.
Nein, nach dem gründlicheren Studium der Funktion ist mir das mit dem Positionszähler schon einigermaßen klar geworden.
Wenn ich die obige Zeile:
Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [eins]);
so schreibe:
Leistung [1] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [1]);
dann müßte es klarer sein. Aber auch dann heißt es: "incompatible types in assignment". Was ist denn da noch falsch?
Oder über den Rückgabewert:
: They return True if successful, False otherwise.
Deshalb klappt die Zuweisung an die Zielvariable nicht.
Es gibt ja gar keinen Rückgabewert, nur die obige Fehlermeldung. Oder bedeutet diese Fehlermeldung schon ein "return False"?
Dann kannst du auch einfach "ReadStr" verwenden. Wenn er dann doch etwas anderes enthält, gibt es einen Laufzeitfehler. Je nach Anwendung ist das OK oder nicht ...
So scheint es. Zwar habe ich in einem kleinen Probe-Programm vorhin problemlos gearbeitet, aber mein großes Programm läuft genau dann nicht mehr, wenn ich die Zeile mit Str2Int einkommentiere, obwohl bei der Übersetzung nichts beanstandet wird (Das ist ja wohl en Laufzeitfehler, oder?).
Was heißt, es läuft nicht mehr?
Laufzeitfehler sehen so ähnlich aus:
foo: sign or digit expected (error #552 at 804a0b6)
Wenn es immer noch um das CGI-Programm geht, sieht man im Browser nur einen internen Fehler (500 oder so), wenn das Progrmam vorzeitig abbricht. Die genaue Fehlermeldung findet man ggf. im Server-Logfile.
Nein, es stürzt nicht ab. Nur wird die html-Ausgabe nicht mehr vollständig aufgebaut, d.h. ich bekomme nicht das, was ich wollte, sondern er schreibt ab einem gewissen Punkt den html-Code nicht mehr weiter.
... Nachseh-Pause ... ;-)
Nun habe ich das mal genauer geprüft: Die Zeile mit dem ReadStr steht in einer Prozedur namens "Best_Leistung", welche wiederum aufgerufen wird in einer Prozedur namens "Auswertung", und diese wird in einer Prozedur namens "AufgabenAusgeben" aufgerufen.
Diese letzte Prozedur (AufgabenAusgeben) wird immer mit aufgerufen, wenn der Benutzer eine Eingabe gemacht hat. Sie dient in erster Linie dazu, den Bildschirm mit den gewünschten Veränderungen neu aufzubauen.
Und genau da, wo die "Best_Leistung" aufgerufen wird, hört der Bildschirmaufbau auf.
Zur noch genaueren Prüfung habe ich mal etwas in eine Probedatei geschrieben::
Append (ProbeDat, '../test/LST/die-Sitzungen/probe.txt'); WriteLn (ProbeDat, Rekord_Datum); Close (ProbeDat);
ReadStr (Rekord_Datum, Das_Rekord_Datum);
Das funktioniert, wenn ich die Datei VOR der ReadStr-Anweisung beschreibe.
Es findet kein weiterer Schreibvorgang statt, wenn ich die Datei NACH der ReadStr-Anweisung beschreiben will.
An der Variable "Rekord_Datum" kann es nicht liegen, denn die wird ja geschrieben, wenn ich sie VOR der ReadStr-Anweisung schreiben lasse.
Sie enthält übrigens den String mit der Zahl der "GetMicroSecondTime"-Zeit der ermittelten bisherigen Bestleistung.
Das funktioniert auch alles bestens. Nur will ich diesen String durch die Prozedur "Zeit_Komponenten_Ausgabe" laufen lassen, deshalb muß sie nach Integer verwandelt werden ...
UUpps: Dabei ist mir aufgefallen, daß ich die Variable "Das_Rekord_Datum" als Integer deklariert hatte, aber sie muß natürlich LongInt sein.
Ohne den Versuch, das alles hier zu beschreiben, wäre mir das wohl kaum aufgefallen. :-)
Nun läßt sich die Probedatei auch NACH der ReadStr-Anweisung beschreiben, und auch alles andere funktioniert wieder einwandfrei.
Roland Goretzki schrieb:
der Fehler lag in der falschen Deklaration einer Variablen, die nicht Integer, sondern LongInt sein mußte:
Ist so etwas auch ein Laufzeitfehler?
Kommt darauf an, was der Fehler war:
- Wenn er beim Compilieren (gpc-Aufruf) auftritt, ist es ein Compile-Fehler (z.B. wenn als var-Parameter Integer statt LongInt übergeben wird oder umgekehrt; während Wert-Parameter automatisch umgewandelt werden).
- Wenn er beim Programmaufruf auftritt, ist es ein Laufzeitfehler, z.B. weil eine Berechnung überläuft, die LongInt erfordern würde.
Du schriebst:
Demnach müßte ich also für das 2. Argument die Variable eins einsetzen:
eins := 1; Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [eins]);
Das erste Argument ist der String, aus dem ich die Zahl haben möchte. Vielleicht ist das 3. Argument der springende Punkt. Mir ist überhaupt nicht klar, weshalb noch ein 3. Argument gebraucht wird, also auch nicht, was da erwartet wird.
Das 3. Argument ist das Ziel, soweit richtig.
Das heißt, daß dort genau dasselbe stehen muß wie das, dem ich es zuweisen möchte? Klingt merkwürdig, habe ich aber im obigen Beispiel probiert, weil mir nichts Besseres einfiel.
Du wunderst dich vermutlich eher über das 2. Argument.
Nein, nach dem gründlicheren Studium der Funktion ist mir das mit dem Positionszähler schon einigermaßen klar geworden.
Wenn ich die obige Zeile:
Leistung [eins] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [eins]);
so schreibe:
Leistung [1] := StrReadInt (Leistungs_Zahl [drei], eins, Leistung [1]);
dann müßte es klarer sein. Aber auch dann heißt es: "incompatible types in assignment". Was ist denn da noch falsch?
Oder über den Rückgabewert:
: They return True if successful, False otherwise.
Deshalb klappt die Zuweisung an die Zielvariable nicht.
Es gibt ja gar keinen Rückgabewert, nur die obige Fehlermeldung.
Da liegen wohl ein paar Missverständnisse vor. Der Rückgabewert ist der Wert, den die Funktion liefert. In diesem Fall ist der Rückgabewert eben ein Boolean (der angibt, ob die Umwandlung erfolgreich war oder nicht) und eben nicht das Ergebnis der Umwandlung. Dieses wird in dem 3. Parameter zurückgeliefert. Deshalb muss als 3. Parameter eben das Ziel (in deinem Fall "Leistung[eins]") übergeben werden -- nicht auch, sondern nur dort, während der Rückgabewert abgefragt werden kann, um Fehler zu erkennen. Wie gesagt, s. das Beispiel in dem Kommentar, dort werden die Zielvariablen ("Size", "Name", ...) ja auch nur an einer Stelle verwendet und die Rückgabewerte im "if" abgefragt.
Der Sinn ist, dass man auf diese Weise mehrere Werte aus einem String auslesen kann (was ja, wie gesagt der Hauptzweck dieser Funktionen ist) und die Fehlerabfrage einfach mit "and" kombinieren kann, damit man nicht für jeden einzelnen Wert eine Fehlerbehandlung schreiben muss (solange es einen nur interessiert, ob die Umwandlungen komplett erfolgreich sind oder nicht).
Oder bedeutet diese Fehlermeldung schon ein "return False"?
Nein, die Fehlermeldung kam ja beim Compilieren und Rückgabewerte ist das, was zur Laufzeit passiert (vgl. oben).
Dann kannst du auch einfach "ReadStr" verwenden. Wenn er dann doch etwas anderes enthält, gibt es einen Laufzeitfehler. Je nach Anwendung ist das OK oder nicht ...
So scheint es. Zwar habe ich in einem kleinen Probe-Programm vorhin problemlos gearbeitet, aber mein großes Programm läuft genau dann nicht mehr, wenn ich die Zeile mit Str2Int einkommentiere, obwohl bei der Übersetzung nichts beanstandet wird (Das ist ja wohl en Laufzeitfehler, oder?).
Was heißt, es läuft nicht mehr?
Laufzeitfehler sehen so ähnlich aus:
foo: sign or digit expected (error #552 at 804a0b6)
Wenn es immer noch um das CGI-Programm geht, sieht man im Browser nur einen internen Fehler (500 oder so), wenn das Progrmam vorzeitig abbricht. Die genaue Fehlermeldung findet man ggf. im Server-Logfile.
Nein, es stürzt nicht ab. Nur wird die html-Ausgabe nicht mehr vollständig aufgebaut, d.h. ich bekomme nicht das, was ich wollte, sondern er schreibt ab einem gewissen Punkt den html-Code nicht mehr weiter.
OK, das passiert, wenn er schon in mitten in der HTML-Ausgabe ist. Trotzdem steht die Fehlermeldung im Apache-Log (/var/log/apache/www.roland-goretzki.de-error_log -- habe mir mal erlaubt nachzusehen :-).
Zur noch genaueren Prüfung habe ich mal etwas in eine Probedatei geschrieben::
Append (ProbeDat, '../test/LST/die-Sitzungen/probe.txt'); WriteLn (ProbeDat, Rekord_Datum); Close (ProbeDat); ReadStr (Rekord_Datum, Das_Rekord_Datum);
Das funktioniert, wenn ich die Datei VOR der ReadStr-Anweisung beschreibe.
Es findet kein weiterer Schreibvorgang statt, wenn ich die Datei NACH der ReadStr-Anweisung beschreiben will.
Ja, so kann man die Fehlerstelle einkreisen, wenn auch umständlich. Mit der Fehlermeldung aus dem Log (oder bei nicht-CGI-Programmen direkt in der Fehlerausgabe) ist oft sofort klar, was los ist. Ansonsten enthält sie auch noch eine Positionsangabe wie "(error #452 at 806407f)". Diese kann man mit folgendem Programm einer Programmzeile zuordnen:
addr2line -e program 806407f
"program" ist dabei das compilierte Programm. Wichtig ist dabei, dass es mit "-g" (Debug-Info) compiliert wurde und seit dem Auftreten des Fehlers nicht verändert wurde (sonst verschieben sich die Positionen).
Frank
Hallo Liste, hallo Frank,
Du schriebst:
Da liegen wohl ein paar Missverständnisse vor. Der Rückgabewert ist der Wert, den die Funktion liefert. In diesem Fall ist der Rückgabewert eben ein Boolean (der angibt, ob die Umwandlung erfolgreich war oder nicht) und eben nicht das Ergebnis der Umwandlung. Dieses wird in dem 3. Parameter zurückgeliefert. Deshalb muss als 3. Parameter eben das Ziel (in deinem Fall "Leistung[eins]") übergeben werden -- nicht auch, sondern nur dort, während der Rückgabewert abgefragt werden kann, um Fehler zu erkennen. Wie gesagt, s. das Beispiel in dem Kommentar, dort werden die Zielvariablen ("Size", "Name", ...) ja auch nur an einer Stelle verwendet und die Rückgabewerte im "if" abgefragt.
Nun kann ich die Funktion korrekt aufrufen. Das hat zwar lange gedauert, aber ich glaube, daß ich es jetzt zum großen Teil verstanden habe: Also, die Funktion liefert NUR den Wert FALSE zurück, wenn keine Zahl aus dem String gelesen werden kann, anderenfalls aber TRUE UND das Ergebnis der Umwandlung.
Um das verstehen zu können, habe ich lange an einem kleinen Programm gebastelt, welches für mich deutlicher aufzeigt, wie es sich verhält:
8---------------------------------------------------------------------------------- Program String_nach_Int;
Uses gpc, stringutils;
Const Letzte_Zahl=5;
Var Zahl, I, J: Integer; Leistung: Array [1 .. Letzte_Zahl] of Integer = ( 7, 14, 34, 44, 77); Leistungs_String: Array [1 .. Letzte_Zahl] of String (20) = ('248', ' 54 b', '5 4b', 'b 54', 'bw lwz');
Zahl_String: String (20);
Begin (* String_nach_Int *) For J := 1 to Letzte_Zahl do Begin I := 1; Write ('Die Zahl ', Leistung [J]); If StrReadInt (Leistungs_String [J], I, Leistung [J]) Then WriteLn (' wird durch ', Leistung [J], ' aus der String-Variablen "', Leistungs_String [J], '" ersetzt.') Else WriteLn (' kann durch keine Zahl aus der String-Variablen "', Leistungs_String [J], '" ersetzt werden.'); End; End (* String_nach_Int *). 8----------------------------------------------------------------------------------
Das Ergebnis: Die Zahl 7 wird durch 248 aus der String-Variablen "248" ersetzt. Die Zahl 14 wird durch 54 aus der String-Variablen " 54 b" ersetzt. Die Zahl 34 wird durch 5 aus der String-Variablen "5 4b" ersetzt. Die Zahl 44 kann durch keine Zahl aus der String-Variablen "b 54" ersetzt werden. Die Zahl 77 kann durch keine Zahl aus der String-Variablen "bw lwz" ersetzt werden.
Daraus schließe ich, daß er solange nach Integer verwandelt, als er von anfang an oder nach führenden Leerzeichen eine Ziffer vorfindet. Sobald dann das erste Nicht-Ziffer-Zeichen auftaucht, bricht er die Verwandlung ab, die aber erfolgreich war, falls überhaupt etwas nach obigen Regeln verwandelt werden konnte.
Was ich aber noch nicht verstehe: Wieso schützt mich das besser vor Fehlern, als mein a-priori-Wissen um den reinen Zifferngehalt des zu verwandelnden Strings?
Schließlich wird in meinem Programm diese Zahl zusammen mit zwei anderen String-Bestandteilen nur in einer Datei abgelegt, um an anderer Stelle wieder ausgelesen und mit einem eigenen Parser (Trennzeichen hatte ich beim Speichern schon gesetzt) in die ursprünglichen Bestandteile zurückverwandelt zu werden.
Woher sollen da, wenn der Parser genau arbeitet (und das tut er), noch irgendwelche mysteriösen Nicht-Ziffer-Zeichen herkommen?
Außerdem: Falls in der 16-stelligen Unix-Zeit doch irgendwo irgendein anderes Zeichen als eine Ziffer auftauchen sollte, würde mir doch StrReadInt keine Warnung geben können, solange am Anfang noch mindestens eine Ziffer steht, oder?
Der Sinn ist, dass man auf diese Weise mehrere Werte aus einem String auslesen kann (was ja, wie gesagt der Hauptzweck dieser Funktionen ist) und die Fehlerabfrage einfach mit "and" kombinieren kann, damit man nicht für jeden einzelnen Wert eine Fehlerbehandlung schreiben muss (solange es einen nur interessiert, ob die Umwandlungen komplett erfolgreich sind oder nicht).
Wenn ich das richtig verstanden habe, nützt mir StrReadInt für meine Zwecke wohl doch nichts, weil ich ja nicht mehrere Werte aus dem betreffenden String auslesen möchte.
Weil Du aber so die Wichtigkeit einer Fehlerbehandlung hervorhebst, habe ich mir nun zum ersten Mal bewußt Gedanken darüber gemacht:
Bisher habe ich beim Programmieren immer all das akribisch auf genaues Funktionieren überprüft, was schon vorhanden war, bevor ich dem Programm weitere Bestandteile hinzugefügt habe.
Zu diesem Zweck habe ich auch immer so wie in dem kleinen Programm "String_nach_Int" Ausgabeanweisungen geschrieben (auch wesentlich komplexere), mit deren Hilfe Fehler schnell gefunden werden konnten.
So ist meine bisherige Erfahrung die, daß all das, was einmal funktioniert, auch in Zukunft immer funktioniert, und wenn es das scheinbar nicht tut, ist der Fehler IMMER in dem neuen Programmbestandteil zu finden, der ja noch nicht so genau geprüft wurde.
Die alten Kontrollen habe ich nach erwiesener Funktionsreinheit immer auch irgendwann, wenn sie wirklich nicht mehr gebraucht wurden, wieder entfernt.
Nun ist allerdings meine "Erfahrung" noch recht klein, und ich lasse mich da gerne eines besseren belehren, falls es gegen diese Vorgehensweise massive Bedenken geben sollte.
Nein, es stürzt nicht ab. Nur wird die html-Ausgabe nicht mehr vollständig aufgebaut, d.h. ich bekomme nicht das, was ich wollte, sondern er schreibt ab einem gewissen Punkt den html-Code nicht mehr weiter.
OK, das passiert, wenn er schon in mitten in der HTML-Ausgabe ist. Trotzdem steht die Fehlermeldung im Apache-Log (/var/log/apache/www.roland-goretzki.de-error_log -- habe mir mal erlaubt nachzusehen :-).
Natürlich, gerne. Dabei fällt mir auf, daß ich nicht einmal Leserechte daran besitze. Muß ich Peter mal fragen, wie ich daran komme.
[ ... ] Ja, so kann man die Fehlerstelle einkreisen, wenn auch umständlich. Mit der Fehlermeldung aus dem Log (oder bei nicht-CGI-Programmen direkt in der Fehlerausgabe) ist oft sofort klar, was los ist. Ansonsten enthält sie auch noch eine Positionsangabe wie "(error #452 at 806407f)". Diese kann man mit folgendem Programm einer Programmzeile zuordnen:
addr2line -e program 806407f
"program" ist dabei das compilierte Programm. Wichtig ist dabei, dass es mit "-g" (Debug-Info) compiliert wurde und seit dem Auftreten des Fehlers nicht verändert wurde (sonst verschieben sich die Positionen).
Das ist gut. Kannte ich noch nicht. Dazu brauch ich natürlich Lesezugriff auf das Log.
Danke für die große Geduld, dadurch lerne ich wirklich sehr viel. :-)
Fröhliche Grüße Roland