Die knifflige letzte Zeile

Hallo Programmierer,

ich häng mal wieder - und diesmal an einem Problem, das an sich nicht so schwer klingt.
Aufgabe: Schreibe ein Programm, das Daten loggt.
Format der Logdatei:

Logdaten 1

Logdaten n

So weit, so gut. Headerangaben sind schnell reingeschrieben, Logging passiert in einer Endlosschleife, Signalhandler ist für SIGINT (strg+c) installiert.
Die Preisfrage ist: wie schaffe ich es, dieses Endtag einzufügen?

Ich hab probiert, in der Signalhandlingroutine den Schreibstrom zu benutzen - das geht nicht (Speicherzugriffsfehler). In der Signalhandlingroutine einen neuen Strom erzeugen? Speicherzugriffsfehler.
Anderer Ansatz: Das Endtag gleich reinschreiben, die Loggingdaten davor „einfügen“. Diese Funktionalität scheint ostream jedoch nicht zu bieten (seekp und anschliessendes write überschreibt nämlich schon vorhandene Daten).

Hat da jemand eine Idee? Kann ja echt nicht sein, dass ich der erste mit dem Problem bin… *bitterlach*

kvida

Hallo Kvida,

Format der Logdatei:

Logdaten 1

Logdaten n

So weit, so gut. Headerangaben sind schnell reingeschrieben,
Logging passiert in einer Endlosschleife, Signalhandler ist
für SIGINT (strg+c) installiert.
Die Preisfrage ist: wie schaffe ich es, dieses Endtag
einzufügen?

Einfach einen Signalhandler installieren,
wie Du schon sagtest :wink:

Ich hab probiert, in der Signalhandlingroutine den
Schreibstrom zu benutzen - das geht nicht
(Speicherzugriffsfehler).

Warum denn nicht? Quelltext wäre hier
hilfreich gewesen.

Hat da jemand eine Idee? Kann ja echt nicht sein,
dass ich der erste mit dem Problem bin… *bitterlach*

Also in Ermangelung eines Quelltextes von
Dir hab ich mal ein kleines Beispiel
versucht, – was auch klappt. Der End-Tag
wird sauber reingeschrieben:

 #include 
 #include 
 #include 
 
 static char \*starttag = "";
 static char \*endtag = "";
 static FILE \*stream = 0;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

 void myHandler (int sig)
{
 fprintf(stream,"\n%s\n", endtag); // Endtag schreiben
 fclose(stream); // File schliessen
 exit(sig);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

 void do\_logging() 
{
 fprintf(stream, "%s\n", starttag); // startag schreiben
 signal(SIGINT, myHandler); // sighandler setzen
 while( !0 ) {
 fprintf(stream, "%066i, %lf, HALLO, \n", 100, 99.99);
 }
 raise(SIGINT); // (kommt nie hier an :wink:
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

 int main(int argc, char \*argv[])
{
 if((stream = fopen("logfile", "w")) != 0) { // file oeffnen
 do\_logging(); // logfile schreiben
 fclose(stream); // ohne ctrlc schliessen
 }
 return 0;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - //

Ich hab zwar stdio statt fstream genommen,
aber dies ist für 90 aus 100 Fällen sowieso die
bessere Wahl (imho) :wink:

Grüße

CMБ

So weit, so gut. Headerangaben sind schnell reingeschrieben,
Logging passiert in einer Endlosschleife, Signalhandler ist
für SIGINT (strg+c) installiert.
Die Preisfrage ist: wie schaffe ich es, dieses Endtag
einzufügen?

Probier mal, aus dem Handler nur ein Flag (zB eine globale Variable) zu setzen, das in der Endlosschleife abgefragt wird. Du könntest dann wenn das Flag gesetzt ist aus der Schleife per break rausspringen und danach einfach das End-Tag schreiben.

Funzt, DANKE! Aber…
Hallo Semjon,

Danke für deinen Code! Ich habs dementsprechend umgeschrieben und siehe da, es klappt auf Anhieb. :smile:
Ich nehme an, mein Fehler lag darin, dass ich den Logger als Klasse deklariert hab. Dadurch hab ich dann ziemlich rumgemurkst, damit die stop-Funktion noch auf den Strom zugreifen kann usw…

Aber wo du grad da bist:

  • Spielt es eigentliche eine Rolle, wo der Signalhandler genau steht? (Vorausgesetzt, es ist nicht in einer Schleife :wink:)

Ich hab zwar stdio statt fstream genommen,
aber dies ist für 90 aus 100 Fällen sowieso die
bessere Wahl (imho) :wink:

  • Warum? *g* Ich hab halt fast nur Professoren, die einem das OOP inkl. Ströme lang und breit vorpredigen… da gewinnt man schon mal den Eindruck, Filedeskriptoren würden überflüssig… :wink:

Danke nochmal!!!

kvida

Aber wo du grad da bist:

  • Spielt es eigentliche eine Rolle, wo der Signalhandler genau
    steht? (Vorausgesetzt, es ist nicht in einer Schleife :wink:)

Wie meinst du das genau? Der Handler selber (also die Funktion) muss halt so deklariert und definiert werden, dass er beim Aufruf von signal() bekannt ist. Der Aufruf von signal() kan prinzipiell so gut wie überall erfolgen. Du musst halt aufpassen, dass der Handler erst zu einem Zeitpunkt aktiv werden kann, zu dem alle für ihn notwendigen Bedingungen erfüllt sind. Es muss in deinem Fall also der File-Deskriptor gültig sein, weil das Programm sonst Mist baut.

Ich hab zwar stdio statt fstream genommen,
aber dies ist für 90 aus 100 Fällen sowieso die
bessere Wahl (imho) :wink:

  • Warum? *g* Ich hab halt fast nur Professoren, die einem das
    OOP inkl. Ströme lang und breit vorpredigen… da gewinnt man
    schon mal den Eindruck, Filedeskriptoren würden überflüssig…

Hinter den Streams in C++ steckt ein weit mächtigeres Konzept als hinter den einfachen Deskriptor-basierten Routinen. Die fstreams bilden praktisch betrachtet einen Wrapper um eine geöffnete Datei und stellen in vielen Fällen einfach keinen großartigen Vorteil dar. Für ein Äquivalent zu Format-Strings von fprintf und Konsorten muss man sogar zu Bibliotheken wie z.B. Boost greifen. Allerdings kann man in Streams auch komplexe Verhaltensmuster verpacken, so dass man nach der notwendigen Vorarbeit die Serialisierung und Deserialisierung von komplexen Objekten einfach per "fs