Fscanf überschreibt falsche Werte

Hallo,
Ich lese folgende Datei aus:

./resources/treeoba.bmp 1 1 000 595 480 025 025
./resources/ballblu.bmp 1 1 001 035 038 600 050
./resources/ballyel.bmp 1 1 001 035 038 600 100

mit folgendem Code:

typedef struct Object {
 char filename[25];
 Sint16 x, y;
 Uint16 w, h;
 Uint16 type; // 0 = hard, 1 = movable, 2 = Save, 3 = Load, 20/21 = Trash
 bool parent; // creates new one if selected
 bool enabled = 1;
} Object;

Object objects[1000];

[...]
 while (fscanf(f, "%23s", &objects[i].filename) != EOF && fscanf(f, "%1d", &objects[i].enabled) != EOF && fscanf(f, "%1d", &objects[i].parent) != EOF) i++;

Den Filename liest er richtig aus. Den Enabled-Status ebenfalls. Und auch den Parentwert. Wie ihr oben sehen könnt sind enabled und Parent = 1 / true. Allerdings ändert er den Wert von Enabled auf False sobald er Parent ausliest!? Setze ich beide Werte auf 0, so liest er beide Werte richtig ein! Was mache ich da jetzt falsch?

Schöne
Grüße Julian

Howdy,

lass dir von deinem Compiler zunächst den Wert sizeof(bool) ausgeben.
Oftmals entspricht dieser nicht sizeof(int), so dass du %d als Formatflag dafuer nicht zur Eingabe verwenden kannst.

Bei der Eingabe des zweiten Wertes wird dann aufgrund der Lage der Elemente in deinem struct, der vorher eingelesene Wert überschrieben.

Gruss
E.

Moin E,
Danke für deine Antwort. Leuchtet mir ein. Allerdings weiß ich nicht, wie ich das Problem umgehen soll :confused: ich könnte anstatt booleans integer verwenden. Scheint mir aber eine unschöne Lösung zu sein. Daher würde ich das beim fscanf gerne als Boolean auslesen. Nur wie ist dafür der Index? Also %b klappt zum beispiel nicht. Kann ich direkt beim % d angeben, wie viel Byte er auslesen soll und die Angabe mit Sizeof bool angeben?

Schöne Grüße
Julian

Hi,

Danke für deine Antwort. Leuchtet mir ein. Allerdings weiß ich
nicht, wie ich das Problem umgehen soll :confused: ich könnte anstatt
booleans integer verwenden.

das zum Einen, aber du koenntest auch zwei temporäre Integer
einlesen und spaeter auf die booleans zuweisen.

ala

 int temp1;
 ... fscanf(f,"%d",&temp1) ...

 x.enabled = 0 != temp1;

welches ohnehin korrekter wäre, denn 0 und 1 sind zunächst einmal nur Werte in deiner Datei (bis zum 1999er C Standard war noch nicht einmal definiert, dass der boolesche Wert „true“ einer 1 entspricht, lediglich, dass „false“ einer 0 entspricht).

Lösung zu sein. Daher würde ich das beim fscanf gerne als
Boolean auslesen. Nur wie ist dafür der Index? Also %b klappt

nein, für bool gibt es das nicht.

In C++ kann man einen int, gefolgt von einem bool, gefolgt von einem String von einem Stream (hier std::cin) wie folgt einlesen:

 int intvar;
 bool boolvar;
 std::string stringvar;

 std::cin \>\> intvar \>\> boolvar \>\> stringvar;

Gruss
E.

Kann ich direkt beim % d angeben, wie viel
Byte er auslesen soll und die Angabe mit Sizeof bool angeben?

Such „length“ in der Referenz für fscanf!

Howdy,

Kann ich direkt beim % d angeben, wie viel
Byte er auslesen soll und die Angabe mit Sizeof bool angeben?

Such „length“ in der Referenz für fscanf!

mal abgesehen davon, dass du wahrscheinlich width und nicht length gemeint hast, hat der TE davon rein gar nichts.

Solltest du anderer Meinung sein, so stell uns hier ein Beispiel ein, welches auf allen Plattformen und allen Byteordern funktioniert (d.h. erfolgreich mit fscanf einen bool einliest).

Gruß
E.

Moin E.,
ich meine schon length. Was der Threaderöffner davon hat, ist die Antwort auf die Frage, ob er bei %d angeben kann, wie lange der Wert sein soll. Abhängig davon, welche Länge ein Boolean-Wert hat, kann er sich aus der Tabelle ein passendes Tierchen aussuchen. Von plattformübergreifend war nie die Rede. Wenn du das sicherstellen willst, kannst du byteweise auslesen (fgets, fgetc, fread).

Die c+±Lösung hierfür ist natürlich ein fstream-Objekt, das Exceptions aufwerfen kann und komfortabler zu handhaben ist als die c-Funktionen.

Gruss
Berchthold

Hi,

Tierchen aussuchen. Von plattformübergreifend war nie die
Rede. Wenn du das sicherstellen willst, kannst du byteweise
auslesen (fgets, fgetc, fread).

doch, das plattformübergreifend ist wichtig, wenn du einen Ratschlag gibst, der allgemein gelten soll.

Das hh zum Beispiel, was vielleicht mit GNU gehen würde, geht aber insbesondere bei aktuellen Microschrott Compilern nicht (Laut MSDN ist es weiterhin nicht implementiert). Wieso also hier jemanden erstmal losschicken und implementieren lassen, bis er daraufhin feststellen muss, dass es mit seinem Compiler nicht geht?

Gruss
E.

PS Formatspec laut MS 2013:

 % [\*] [width] [{h | l | ll | I64 | L}]type

Somit gilt dort sowohl fuer printf als auch fuer scanf: The hh, j, z, and t length prefixes are not supported.

Moin,

int temp1;
… fscanf(f,"%d",&temp1) …

x.enabled = 0 != temp1;

funktioniert genauso wenig -.-
Er lädt einfach irgendwas. Manchmal bekommt er sogar den ersten und den zweiten Wert geladen! Doch dann ändere ich sie und es kommen trotzdem die gleichen Werte wie davor raus -.-
Irgendwie check ich nicht ganz, was er da überhaupt macht… Ich hab probeweise mal die Daten als Integer gespeichert und geladen, das gleiche Ergebnis. Nachdem ich die ersten drei Werte gelesen habe kommt interessanter weiser als nächster Wert 480! Kp. wo er sich diesen wieder aus den Finger saugt …

Also es liegt wohl nicht nur an den Booleans. Wenn ich ein Integer lade, dachte ich, dass er solange im String weitergeht, bis ein Integer startet und dann endet, wenn der endet, also in diesem Falle zwischen den zwei Leerzeichen… Wieso klappt das hier aber überhaupt nicht?

Ich diskutier jetzt ganz bestimmt nicht mit dem C-Forums-Streithahn darüber, ob jedes Programm plattformübergreifend sein muss. Hier geht’s um eine Lösung für GURKE. Mein Verständnis von wer-weiss-was ist, dass man gemeinsam für eine Lösung sorgen soll, und der Fragesteller von unterschiedlichen Ansätzen und Ansichten profitieren kann.

Howdy,

Also es liegt wohl nicht nur an den Booleans. Wenn ich ein
Integer lade, dachte ich, dass er solange im String
weitergeht, bis ein Integer startet und dann endet, wenn der
endet, also in diesem Falle zwischen den zwei Leerzeichen…
Wieso klappt das hier aber überhaupt nicht?

es liegt auch mit daran, dass das PRE das bei dir so formatiert hat, dass man nicht gleich gesehen hat, dass du gar nicht den Rest der Zeile eingelesen hast.

 while (fscanf(f, "%23s", objects[i].filename) != EOF 
 && fscanf(f, "%1d", &objects[i].enabled) != EOF 
 && fscanf(f, "%1d%\*[^\n]\n", &objects[i].parent) != EOF) 

und auch daran, dass du ein & zuviel hattest.

(in diesem Fall wären enabled und parent ints)

Gruß
E.

OT: Netiquette?
Hi,

Ich diskutier jetzt ganz bestimmt nicht mit dem
C-Forums-Streithahn darüber, ob jedes Programm

richtig ist, dass ich seit Jahren, also auch schon vor meiner Umbenennung hier derjenige mit den meisten und zgT auch richtigen Antworten bin. Dass darunter auch die eine oder andere Bemerkung ist, die einem Fragestellenden oder Antwortenden nicht passt, ist völlig normal. Weshalb du daraus auf Streithahn schließt, magst du selbst beurteilen. Ich persönlich finde dieses Statement nicht angebracht und meine AG nennen diese Fähigkeit auch gänzlich anders :wink:

plattformübergreifend sein muss. Hier geht’s um eine Lösung
für GURKE. Mein Verständnis von wer-weiss-was ist, dass man

Wieviel hast du zu einer funktionierenden Lösung für Gurke beigetragen?
Hast du ein funktionierendes Beispiel vorgetragen?
Konntest du sein Problem lösen?

Deine Antwort wäre ok gewesen, wenn du darauf hingewiesen hättest, dass sie nicht portabel ist oder wenn du den Fragesteller vorher gefragt hättest, mit welcher Compiler/OS Version er arbeitet? Da man dieses hier in der Regel nicht macht, sollten portable Antworten gegeben werden, denn ansonsten verschwendest du die Zeit des Fragestellers, welcher ja zunächst einmal davon ausgehen muss, dass deine Antwort bei ihm funktioniert.

Gruß
E.