Discussion:
Anfaengerfrage Signalhandling
(zu alt für eine Antwort)
Volker Englisch
2014-06-16 16:40:34 UTC
Permalink
Hallo,

ich versuche gerade, ein ursprünglich in Pascal geschriebenes
Progrämmchen nach C umzusetzen (da der Pascal-Compiler nur statisch
linken kann und riesige Binaries ausspuckt).

Das Teil macht nichts anderes, als aus einem File oder von stdin zu
lesen und die Ausgabe nach /dev/tty zu senden. Davor und danach wird
das Terminal umgeschaltet, sodaß der Ausdruck an den angeschlossenen
Drucker geht. Dazwischen erfolgt noch eine Umsetzung einiger
Sonderzeichen. Funktioniert auch so weit. Nun hätte ich gerne bei einem
Abbruch mit Ctrl-C noch die Sequenz zum Zurückschalten gesendet. Unten
die (verkürzte) Version, die zumindest kompiliert, wenn auch mit der
Fehlermeldung "tprint.c: In function 'main': tprint.c:79: warning:
passing argument 2 of 'signal' makes pointer from integer without a
cast".

Inzwischen habe ich einiges dazu im Netz gefunden, nämlich das Handling
in eine Funktion auszulagern. Aber egal, ob ich am Anfang einen
Prototyp einer Funktion und die Funktion selbst ans Ende schreibe, oder
gleich die Funktion an den Anfang: Der Compiler meckert mich
grundsätzlich an, daß er "terminal" nicht kennt.

Frage eines in C wenig bedarften: Wo liegt mein Denkfehler?

V*

--------------------------------------------------------------

#include <stdio.h>
#include <signal.h>

char *PASSTHRU_EIN = "\e[5i";
char *PASSTHRU_AUS = "\e[4i";

|void sighandler (void);
|{
| fprintf ( terminal, PASSTHRU_AUS );
| ...
|}
^^^^^^^^^^^^^^^
Hier bekomme ich den Fehler, daß "terminal" unbekannt ist.

int umwandlung(int ein)
{
int aus;
switch(ein)
{
case 171: aus = 174; break; /* OFw nach links */
[...]
default: aus = ein; break;
}
return ( aus );
}

/**********************************************************************/
/* HAUPTPROGRAMM */
/**********************************************************************/

int main ( int argc, char *argv[] )
{
int x;
FILE *terminal;
terminal = fopen ( "/dev/tty", "w" );
if ( terminal == NULL )
{
printf ( "Kann Terminal nicht öffnen\n" );
return 2;
}
signal(SIGINT, fprintf ( terminal, PASSTHRU_AUS ) );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^ Gibt Hinweis beim Comilieren

fprintf ( terminal, PASSTHRU_EIN );
if ( argc >= 2 ) /* Datei wird angegeben */
{
FILE *datei;
datei = fopen ( argv[1], "r" );
if ( datei == NULL )
{
printf ( "Kann Datei nicht öffnen\n" );
return 1;
}
else
{
while ( ( x = fgetc ( datei ) ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
fclose ( datei );
}
}
else /* Keine Datei angegeben, Stdin lesen */
{
while ( ( x = getchar() ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
}
if ( x != 12 )
{
fputc ( 12, terminal);
}
fprintf ( terminal, PASSTHRU_AUS );
fclose (terminal );
}
Rainer Weikusat
2014-06-16 20:12:10 UTC
Permalink
Post by Volker Englisch
ich versuche gerade, ein ursprünglich in Pascal geschriebenes
Progrämmchen nach C umzusetzen (da der Pascal-Compiler nur statisch
linken kann und riesige Binaries ausspuckt).
Das Teil macht nichts anderes, als aus einem File oder von stdin zu
lesen und die Ausgabe nach /dev/tty zu senden. Davor und danach wird
das Terminal umgeschaltet, sodaß der Ausdruck an den angeschlossenen
Drucker geht. Dazwischen erfolgt noch eine Umsetzung einiger
Sonderzeichen. Funktioniert auch so weit. Nun hätte ich gerne bei einem
Abbruch mit Ctrl-C noch die Sequenz zum Zurückschalten gesendet. Unten
die (verkürzte) Version, die zumindest kompiliert, wenn auch mit der
passing argument 2 of 'signal' makes pointer from integer without a
cast".
Inzwischen habe ich einiges dazu im Netz gefunden, nämlich das Handling
in eine Funktion auszulagern. Aber egal, ob ich am Anfang einen
Prototyp einer Funktion und die Funktion selbst ans Ende schreibe, oder
gleich die Funktion an den Anfang: Der Compiler meckert mich
grundsätzlich an, daß er "terminal" nicht kennt.
Frage eines in C wenig bedarften: Wo liegt mein Denkfehler?
V*
NB: Ich gehe mal von einer UNIX(*)-Umgebung aus, weil Dein Programm
ueber strikt-konformes ISO-C hinausgeht und es sinnvollere Antworten
ermoeglicht, als wenn man sich auf 'C-Signale' beschraenkt.
Post by Volker Englisch
--------------------------------------------------------------
#include <stdio.h>
#include <signal.h>
char *PASSTHRU_EIN = "\e[5i";
char *PASSTHRU_AUS = "\e[4i";
|void sighandler (void);
|{
| fprintf ( terminal, PASSTHRU_AUS );
| ...
|}
^^^^^^^^^^^^^^^
Hier bekomme ich den Fehler, daß "terminal" unbekannt ist.
Da die ein Objekt dieses Namens 'bis hier hin' weder deklariert noch
definiert wurde, ist das nicht ueberraschend. SIGINT ist ein asychrones
Signal, dh es kann zu jedem Zeitpunkt der Programmausfuehrung
auftreten. Weil dieser 'Signalverarbeiter' deshalb nicht 'signalsichere'
Funktionen unterbrechen kann und selber eine aufruft, ist das Verhalten
undefiniert. Selbst wenn man davon absieht, taete das wahrscheinlich
nicht, was es sollte, denn es schiebt die Escape-Sequenze
('Ausbruchsfolge' ist mir zu abstrus) an der momentanen Stelle in den
Ausgabepuffer des streams _und setzt danach die Programm-Ausfuerung
fort_.

Du koenntest in dieser Funktion ein globales flag setzen (Typ 'volatile
sig_atomic_t', fuer praktische Zwecke tut es 'volatile int' auch) und
dieses aus Deiner Hauptschleife ueberpruefen.

[...]
Post by Volker Englisch
/**********************************************************************/
/* HAUPTPROGRAMM */
/**********************************************************************/
int main ( int argc, char *argv[] )
{
int x;
FILE *terminal;
terminal = fopen ( "/dev/tty", "w" );
if ( terminal == NULL )
{
printf ( "Kann Terminal nicht öffnen\n" );
return 2;
}
signal(SIGINT, fprintf ( terminal, PASSTHRU_AUS ) );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^ Gibt Hinweis beim Comilieren
Das uebergibt den Rueckgabewert des fprintf-Aufrufes an signal und der
hat den falschen Type fuer einen signal handler.

Am Rande: Wenn man ohnehin keine formatierte Ausgabe machen will, kann
man statt

fprintf(terminal, string)

auch

fputs(string, terminal)

benutzen.
Post by Volker Englisch
fprintf ( terminal, PASSTHRU_EIN );
if ( argc >= 2 ) /* Datei wird angegeben */
{
FILE *datei;
datei = fopen ( argv[1], "r" );
if ( datei == NULL )
{
printf ( "Kann Datei nicht öffnen\n" );
return 1;
}
else
{
while ( ( x = fgetc ( datei ) ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
fclose ( datei );
}
}
else /* Keine Datei angegeben, Stdin lesen */
{
while ( ( x = getchar() ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
}
if ( x != 12 )
{
fputc ( 12, terminal);
}
fprintf ( terminal, PASSTHRU_AUS );
fclose (terminal );
}
Streams werden bei Programm-Ende automatisch geschlossen, dh die
fclose-Aufrufe sind nicht notwendig. Du kannst uebrigens aus Deinen
beiden Hauptscleifen eine machen, indem Du

if (argc > 1) {
datei = fopen(...);
.
.
.
} else datei = stdin;

benutzt.
Juergen Ilse
2014-06-17 03:00:00 UTC
Permalink
Hallo,
Post by Volker Englisch
V*
--------------------------------------------------------------
#include <stdio.h>
#include <signal.h>
char *PASSTHRU_EIN = "\e[5i";
char *PASSTHRU_AUS = "\e[4i";
|void sighandler (void);
|{
| fprintf ( terminal, PASSTHRU_AUS );
| ...
|}
^^^^^^^^^^^^^^^
Hier bekomme ich den Fehler, daß "terminal" unbekannt ist.
Du hast ja "terminal" auch nirgends definiert. fprintf() erwartet ein
File-Handle einer geoeffneten Datei als Argument, und das uebergibst
du hier einfach nicht.
Post by Volker Englisch
int umwandlung(int ein)
{
int aus;
switch(ein)
{
case 171: aus = 174; break; /* OFw nach links */
[...]
default: aus = ein; break;
}
return ( aus );
}
/**********************************************************************/
/* HAUPTPROGRAMM */
/**********************************************************************/
int main ( int argc, char *argv[] )
{
int x;
FILE *terminal;
terminal = fopen ( "/dev/tty", "w" );
if ( terminal == NULL )
{
printf ( "Kann Terminal nicht öffnen\n" );
return 2;
}
signal(SIGINT, fprintf ( terminal, PASSTHRU_AUS ) );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^ Gibt Hinweis beim Comilieren
hier rufst du signal mit dem Signal SIGNINT und dem *Rueckgabewert* des
Funktionsaufrufs von fprintf(...) auf, was natuerlich voelliger Unfug ist.
Die Funktion signal() erwartet als 2. Parameter eine Funktion, die selbst
etwas vom Typ int als Parameter erwartet und nichts (sprich: void) zurueck-
gibt. Du musst einen entsprechenden Signal-Handler schreiben (eine Funktion
mit einem solchen Prototyp) und dann die Funktion (ohne Parameter) als
Aufrufparameter an signal() uebergeben:

void sighandler(int) {
fprintf ( terminal, PASSTHRU_AUS );
}
...
signal(SIGINT, sighandler);
...

Dann muesste die Warnung (die der Compiler voellig zu recht erzeugte)
weg sein. Allerdings ist nicht unbedingt sichergestellt, dass das hier
auch so funktioniert, denn es ist nicht garantiert, dass der Aufruf von
Library-Funktionen aus Signalhandlern heraus wirklich funktioniert ...
Post by Volker Englisch
fprintf ( terminal, PASSTHRU_EIN );
Hierwirst du wieder den selben Fehler erhalten wie oben:
terminal ist nicht definiert ...
Post by Volker Englisch
if ( argc >= 2 ) /* Datei wird angegeben */
{
FILE *datei;
datei = fopen ( argv[1], "r" );
if ( datei == NULL )
{
printf ( "Kann Datei nicht öffnen\n" );
return 1;
}
else
{
while ( ( x = fgetc ( datei ) ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
fclose ( datei );
}
}
else /* Keine Datei angegeben, Stdin lesen */
{
while ( ( x = getchar() ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
}
if ( x != 12 )
{
fputc ( 12, terminal);
}
fprintf ( terminal, PASSTHRU_AUS );
fclose (terminal );
}
Du kannst dir hier durchaus auch n och Aufwand sparen: Fuer den Fall
"von Standardeingabe lesen" und den Fall "aus Datei lesen" muss ja
eigentlich *exakt* *das* *selbe* passieren, nur wird in ersterem Fall
aus dem (bereits geoeffneten) File stdin gelesen, in letzterem Fall
aus dem File, den du ggfs. oeffnest.

Wie waere es demnach einfach mit etwas wie:

FILE *datei = stdin;
if ( argc >= 2 ) /* Datei wird angegeben */
{
datei = fopen ( argv[1], "r" );
if ( datei == NULL )
{
printf ( "Kann Datei nicht öffnen\n" );
return 1;
}
}
while ( ( x = fgetc ( datei ) ) != EOF )
{
fputc ( umwandlung(x), terminal );
}
if (datei == stdin) fclose ( datei );
...

Ich habe im wesentlichen im selben Stil geschrieben, wie du, habe aber
gegenueber deinem Code 40% eingespart, indem ich die (eigentlich ueber-
fluessige) Unterscheidung beider Faelle nicht gemacht habe.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Volker Englisch
2014-06-17 12:32:11 UTC
Permalink
Danke Jürgen, danke Rainer!

Danke für Eure vielen Tipps. Ich habe mich mal bemüht, das umzusetzen.
Siehe am Ende des Postings. Ich bekomme nun immer noch den Fehler:

tprint.c: In function 'sighandler':
tprint.c:119: error: parameter name omitted
tprint.c:121: error: 'terminal' undeclared (first use in this function)
tprint.c:121: error: (Each undeclared identifier is reported only once
tprint.c:121: error: for each function it appears in.)

Ich verstehe zwar den Grund für den Fehler, weiß aber noch nicht, wie
ich das anders lösen könnte.

Das File "terminal" kann ich doch erst am Anfang der Hauptschleife
öffnen, oder?

V*

--------------------------- schnipp ----------------------------------

#include <stdio.h>
#include <signal.h>

char *PASSTHRU_EIN = "\e[5i";
char *PASSTHRU_AUS = "\e[4i";

void sighandler(int);

/**********************************************************************/
/* UMWANDLUNG - Wandlung der Sonderzeichen von LATIN1 nach CP850 */
/**********************************************************************/

int umwandlung(int ein)
{
int aus;
switch(ein)
{
case 196: aus = 142; break; /* Ä */
case 214: aus = 153; break; /* Ö */
case 220: aus = 154; break; /* Ü */
case 228: aus = 132; break; /* ä */
case 246: aus = 148; break; /* ö */
case 252: aus = 129; break; /* ü */
case 223: aus = 225; break; /* ß */
case 161: aus = 173; break; /* ! verkehrt herum */
case 162: aus = 155; break; /* durchgestrichenes kleines c */
case 163: aus = 156; break; /* Pfund-Zeichen */
case 165: aus = 157; break; /* Yen-Zeichen */
case 171: aus = 174; break; /* OFw nach links */
case 172: aus = 170; break; /* Nicht-Zeichen */
case 176: aus = 248; break; /* Grad-Zeichen */
case 177: aus = 241; break; /* Plus-Minus */
case 178: aus = 253; break; /* Hoch-2 */
case 181: aus = 230; break; /* Mikro */
case 183: aus = 250; break; /* Punkt in der Mitte */
case 187: aus = 175; break; /* OFw nach rechts */
case 188: aus = 172; break; /* Viertel */
case 189: aus = 171; break; /* Halb */
case 191: aus = 168; break; /* ? verkehrt herum */
case 197: aus = 143; break; /* A mit Kringel */
case 198: aus = 198; break; /* AE */
case 199: aus = 128; break; /* C mit Schwänzchen */
case 201: aus = 144; break; /* E mit Acute */
case 224: aus = 133; break; /* a mit Grave */
case 226: aus = 131; break; /* a mit Hütchen */
case 229: aus = 134; break; /* a mit Kringel */
case 231: aus = 135; break; /* c mit Schwänzchen */
case 232: aus = 138; break; /* e mit Grave */
case 234: aus = 136; break; /* e mit Hütchen */
case 235: aus = 137; break; /* e mit Doppelpünktchen */
case 236: aus = 141; break; /* i mit Grave */
case 238: aus = 140; break; /* i mit Hütchen */
case 239: aus = 139; break; /* i mit Doppelpünktchen */
case 240: aus = 235; break; /* eine Art Delta */
case 241: aus = 164; break; /* n mit Hilde äh Tilde */
case 242: aus = 149; break; /* o mit Grave */
case 244: aus = 244; break; /* o mit Hütchen */
case 247: aus = 246; break; /* Geteilt-Zeichen */
case 249: aus = 151; break; /* u mit Grave */
case 251: aus = 150; break; /* u mit Hütchen */
case 255: aus = 152; break; /* y mit Doppelpünktchen */
default: aus = ein; break;
}
return ( aus );
}

/**********************************************************************/
/* HAUPTPROGRAMM */
/**********************************************************************/

int main ( int argc, char *argv[] )
{
int x;

FILE *terminal;
terminal = fopen ( "/dev/tty", "w" );

if ( terminal == NULL )
{
printf ( "Kann Terminal nicht öffnen\n" );
return 2;
}

signal(SIGINT, sighandler (terminal));
fputs ( PASSTHRU_EIN , terminal );
FILE *datei = stdin;

if ( argc >= 2 ) /* Datei wird angegeben */
{
FILE *datei;
datei = fopen ( argv[1], "r" );
if ( datei == NULL )
{
printf ( "Kann Datei nicht öffnen\n" );
return 1;
}
}

while ( ( x = fgetc ( datei ) ) != EOF )
{
fputc ( umwandlung(x), terminal );
}

if (datei == stdin) fclose ( datei );

if ( x != 12 )
{
fputc ( 12, terminal);
}

fputs ( PASSTHRU_AUS , terminal );
fclose (terminal );
}

/**********************************************************************/
/* SIGNAL HANDLER */
/**********************************************************************/

void sighandler(int)
{
fputs ( PASSTHRU_AUS , terminal );
raise (SIGINT);
}
Thomas Richter
2014-06-18 07:31:55 UTC
Permalink
Post by Volker Englisch
Danke Jürgen, danke Rainer!
Danke für Eure vielen Tipps. Ich habe mich mal bemüht, das umzusetzen.
tprint.c:119: error: parameter name omitted
tprint.c:121: error: 'terminal' undeclared (first use in this function)
tprint.c:121: error: (Each undeclared identifier is reported only once
tprint.c:121: error: for each function it appears in.)
Ich verstehe zwar den Grund für den Fehler, weiß aber noch nicht, wie
ich das anders lösen könnte.
Das File "terminal" kann ich doch erst am Anfang der Hauptschleife
öffnen, oder?
Bitte lies noch einmal alle Hinweise! Was Du hier tust ist eine *dumme
Idee*(tm).
Post by Volker Englisch
void sighandler(int)
{
fputs ( PASSTHRU_AUS , terminal );
raise (SIGINT);
}
Das wird so nicht funktionieren, und das kann so nicht funktionieren.
Bitte nochmal alle Hinweise genau lesen. Bevor ich darauf eingehe, warum
das nicht compiliert, ist es erstmal wichtig zu verstehen, warum das
nicht funktioniert - selbst wenn man es zum Compilieren bekommt.

Das Signal kann *irgendwann* im Programm kommen, egal wann. Insbesondere
kann es dann kommen, wenn sich Dein Programm gerade in der
Ausgaberoutine befindet, also selbst das "Terminal" benutzt. In diesem
Falle wird die Druckfunktion der Standardbibliothek von sich selbst
unterbrochen - und die Hölle bricht los.

Wie schon geschrieben wurde: Setze stattdessen im Signalhandler ein Flag
und tue sonst *nichts*. Im Hauptprogramm kann man dieses Flag
überprüfen, und falls es gesetzt ist, schreibe den noch fehlenden String
und beende das Programm.

Der Grund warum das nicht compiliert ist dass "terminal" ein Objekt ist,
welches eben nur innerhalb von main() sichtbar ist, da es innerhalb der
Klammern von main() deklariert ist. sighandler() ist aber eine
eigenständige Funktion.

Grüße,
Thomas
Volker Englisch
2014-06-18 10:18:54 UTC
Permalink
Post by Thomas Richter
Bitte lies noch einmal alle Hinweise! Was Du hier tust ist eine *dumme
Idee*(tm).
Done. Ich denke, ich habe es wenigstens ein bisschen verstanden.
Post by Thomas Richter
Das Signal kann *irgendwann* im Programm kommen, egal wann. Insbesondere
kann es dann kommen, wenn sich Dein Programm gerade in der
Ausgaberoutine befindet, also selbst das "Terminal" benutzt. In diesem
Falle wird die Druckfunktion der Standardbibliothek von sich selbst
unterbrochen - und die Hölle bricht los.
Ok.
Post by Thomas Richter
Wie schon geschrieben wurde: Setze stattdessen im Signalhandler ein Flag
und tue sonst *nichts*. Im Hauptprogramm kann man dieses Flag
überprüfen, und falls es gesetzt ist, schreibe den noch fehlenden String
und beende das Programm.
Siehe unten. Ein erster Test ist mal gar nicht so schlecht verlaufen.
Vielleicht begreife ich die Thematik ja doch noch ;-)
Post by Thomas Richter
Der Grund warum das nicht compiliert ist dass "terminal" ein Objekt ist,
welches eben nur innerhalb von main() sichtbar ist, da es innerhalb der
Klammern von main() deklariert ist. sighandler() ist aber eine
eigenständige Funktion.
Abgesehen vom aktuellen Fall, wie würde "man" das lösen? Aus Pascal
kenne ich das so, daß ich aus der Hauptschleife eine Funktion aufrufen
kann und die Funktion dann ein in der Hauptschleife geöffnetes File
"kennt".

So, in abgekürzter Form mein Progrämmchen. Passt es so, oder habe ich
immer noch einen (Denk-) Fehler drin?

V*

#include <stdio.h>
#include <signal.h>

char *PASSTHRU_EIN = "\e[5i";
char *PASSTHRU_AUS = "\e[4i";

volatile sig_atomic_t sigflag;

/**********************************************************************/
/* UMWANDLUNG - Wandlung der Sonderzeichen von LATIN1 nach CP850 */
/**********************************************************************/

int umwandlung(int ein)
{
int aus;
switch(ein)
{
[...]
default: aus = ein; break;
}
return (aus);
}

/**********************************************************************/
/* HAUPTPROGRAMM */
/**********************************************************************/

int main (int argc, char *argv[])
{
int x;

FILE *terminal;
terminal = fopen ("/dev/tty", "w");

if (terminal == NULL)
{
printf ("Kann Terminal nicht öffnen\n");
return 2;
}

fputs (PASSTHRU_EIN , terminal);
FILE *datei = stdin;

if (argc >= 2) /* Datei wird angegeben */
{
FILE *datei;
datei = fopen (argv[1], "r");
if (datei == NULL)
{
printf ("Kann Datei nicht öffnen\n");
return 1;
}
}

while ((x = fgetc (datei)) != EOF)
{
if (!sigflag)
{
fputc (umwandlung(x), terminal);
}
else
{
fputs (PASSTHRU_AUS , terminal);
return 3;
}
}

if (datei == stdin) fclose (datei);

if (x != 12)
{
fputc ( 12, terminal);
}

fputs (PASSTHRU_AUS , terminal);
fclose (terminal );
}
Rainer Weikusat
2014-06-18 19:31:29 UTC
Permalink
***@rsli.de (Volker Englisch) writes:

[...]

Diesmal fehlt ein sigint-handler voellig. Richtig sollte er ungefaehr so
aussehen:

static void verdammte_hacke(int unused)
{
sigflag = 1;
}

mit einem entsprechenden

signal(SIGINT, verdammte_hacke)

im Hauptprogramm.
Post by Volker Englisch
while ((x = fgetc (datei)) != EOF)
{
if (!sigflag)
{
fputc (umwandlung(x), terminal);
}
else
{
fputs (PASSTHRU_AUS , terminal);
return 3;
}
}
Warum nicht

while ((x = fgetc(datei)) != EOF && !sigflag)
fputc(umwandlung(x), terminal);
Post by Volker Englisch
if (datei == stdin) fclose (datei);
Das sollte vermutlich datei != stdin sein, spielt aber praktisch keine
Rolle weil beide fclose-Aufrufe ueberfluessig sind.
Post by Volker Englisch
if (x != 12)
{
fputc ( 12, terminal);
}
fputs (PASSTHRU_AUS , terminal);
fclose (terminal );
Falls Du das Programm mit dem 'richtigen' (ueblichen) exit status fuer
'unterbrochen' beenden moechtest, koenntest Du hier

if (sigflag) {
signal(SIGINT, SIG_DFL);
raise(SIGITN);
}

einfuegen.
Volker Englisch
2014-06-19 16:44:23 UTC
Permalink
Post by Rainer Weikusat
[...]
Diesmal fehlt ein sigint-handler voellig. Richtig sollte er ungefaehr so
Ich dachte, es genügt, einfach in der Verarbeitungsschleife den
passenden Wert in den Datenstrom einzufügen, wenn das Signal anliegt.
Post by Rainer Weikusat
while ((x = fgetc(datei)) != EOF && !sigflag)
fputc(umwandlung(x), terminal);
Post by Volker Englisch
if (datei == stdin) fclose (datei);
Weil ich diese Formulierungsmöglichkeit noch nicht kannte :-(
Post by Rainer Weikusat
if (sigflag) {
fputs(PASSTHRU_AUS, terminal);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Post by Rainer Weikusat
signal(SIGINT, SIG_DFL);
raise(SIGITN);
}
Das hab ich jetzt an dieser Stelle noch eingefügt. Hoffe, das paßt.

Danke für die Geduld.

V*
Rainer Weikusat
2014-06-19 17:39:09 UTC
Permalink
[...]
Post by Volker Englisch
Post by Rainer Weikusat
if (sigflag) {
fputs(PASSTHRU_AUS, terminal);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Post by Rainer Weikusat
signal(SIGINT, SIG_DFL);
raise(SIGITN);
}
Das hab ich jetzt an dieser Stelle noch eingefügt. Hoffe, das paßt.
Der Gedanke dabei war eigentlich, die Verarbeitungsschleife zu beenden,
den 'normalen' 'setzte alles zurueck'-Code auszufuehren (in dem
PASSTHRU_AUS enthalten war) und danach diesen Block einzufuegen.
Volker Englisch
2014-06-20 05:49:13 UTC
Permalink
Post by Rainer Weikusat
[...]
Post by Volker Englisch
Post by Rainer Weikusat
if (sigflag) {
fputs(PASSTHRU_AUS, terminal);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Post by Rainer Weikusat
signal(SIGINT, SIG_DFL);
raise(SIGITN);
}
Das hab ich jetzt an dieser Stelle noch eingefügt. Hoffe, das paßt.
Der Gedanke dabei war eigentlich, die Verarbeitungsschleife zu beenden,
den 'normalen' 'setzte alles zurueck'-Code auszufuehren (in dem
PASSTHRU_AUS enthalten war) und danach diesen Block einzufuegen.
Beispiel: User startet sehr langen Druckvorgang, merkt, dass es der
falsche war, will abbrechen und drückt CTRL-C. Damit sollte eigentlich
die Schleife sofort beendet werden...
Juergen Ilse
2014-06-20 10:50:51 UTC
Permalink
Hallo,
Post by Volker Englisch
Beispiel: User startet sehr langen Druckvorgang, merkt, dass es der
falsche war, will abbrechen und drückt CTRL-C. Damit sollte eigentlich
die Schleife sofort beendet werden...
Die Anweisung "break" ist dir unbekannt?

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Volker Englisch
2014-06-22 16:15:44 UTC
Permalink
Post by Juergen Ilse
Post by Volker Englisch
Beispiel: User startet sehr langen Druckvorgang, merkt, dass es der
falsche war, will abbrechen und drückt CTRL-C. Damit sollte eigentlich
die Schleife sofort beendet werden...
Die Anweisung "break" ist dir unbekannt?
Ja, schon. Der Witz ist aber, vor dem Terminieren noch etwas
auszugeben, das das zu dem Zeitpunkt durchleitende Terminal wieder
zurücksetzt...

V*
Juergen Ilse
2014-06-23 04:17:01 UTC
Permalink
Hallo,
Post by Volker Englisch
Post by Juergen Ilse
Post by Volker Englisch
Beispiel: User startet sehr langen Druckvorgang, merkt, dass es der
falsche war, will abbrechen und drückt CTRL-C. Damit sollte eigentlich
die Schleife sofort beendet werden...
Die Anweisung "break" ist dir unbekannt?
Ja, schon. Der Witz ist aber, vor dem Terminieren noch etwas
auszugeben, das das zu dem Zeitpunkt durchleitende Terminal wieder
zurücksetzt...
Ich meinte das C-Statement "break", mit dem du die Schleife terminieren
kannst, ohne auch gleich das Programm zu beenden.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Stefan Ram
2014-06-23 13:15:28 UTC
Permalink
Post by Juergen Ilse
Post by Juergen Ilse
Die Anweisung "break" ist dir unbekannt?
Ich meinte das C-Statement "break"
»break;« ist eine Anweisung (a jump-statement, N1570 6.8.6p1).
»break« ist ein Schlüsselwort (a keyword, N1570 6.4.1p1).
Claus Reibenstein
2014-06-23 19:30:43 UTC
Permalink
Post by Stefan Ram
Post by Juergen Ilse
Ich meinte das C-Statement "break"
»break;« ist eine Anweisung (a jump-statement, N1570 6.8.6p1).
»break« ist ein Schlüsselwort (a keyword, N1570 6.4.1p1).
Und »Korinthen« sind Rosinen aus der Rebsorte Korinthiaki.

Gruß
Claus
Juergen Ilse
2014-06-23 19:44:48 UTC
Permalink
Hallo,
Post by Claus Reibenstein
Post by Stefan Ram
Post by Juergen Ilse
Ich meinte das C-Statement "break"
»break;« ist eine Anweisung (a jump-statement, N1570 6.8.6p1).
»break« ist ein Schlüsselwort (a keyword, N1570 6.4.1p1).
Und »Korinthen« sind Rosinen aus der Rebsorte Korinthiaki.
Im Grunde genommen hatte er ja recht, auch wenn sein Beitrag in diesem
Thread eher hochgradig kontraproduktiv gewesen sein duerfte (weil fuer
den Fragesteller nicht im geringsten hilfreich). Auch wenn meine Wortwahl
im von ihm kritisierten Beitrag nicht korrekt war (das weiss ich selber)
war sie IMHO doch so, dass der Beitrag (hoffentlich) fuer den OP hilf-
reich war, und das war mir in dem Fall wichtiger.

Tschuess,
Juergen Ilse (***@usenet-verwaltung.de)
--
Ein Domainname ist nur ein Name, nicht mehr und nicht weniger.
Wer mehr hineininterpretiert, hat das Domain-Name-System nicht
verstanden.
Rainer Weikusat
2014-06-23 20:04:45 UTC
Permalink
Post by Juergen Ilse
Post by Claus Reibenstein
Post by Stefan Ram
Post by Juergen Ilse
Ich meinte das C-Statement "break"
»break;« ist eine Anweisung (a jump-statement, N1570 6.8.6p1).
»break« ist ein Schlüsselwort (a keyword, N1570 6.4.1p1).
Und »Korinthen« sind Rosinen aus der Rebsorte Korinthiaki.
Im Grunde genommen hatte er ja recht,
Nicht wirklich. 'break' ist in C ein Schluesselwort, eine bestimmte
Sorte von Token, die syntaktisch auch Bezeichner sein koennten, aber
nicht als Bezeichner benutzt werden duerfen, weil sie reserviert
sind. 'Schluesselworte' und 'Bezeichner' sind Dinge, die waehrend der
lexikalischen Analyse eines in C geschriebenen (Quell-)Textes eine Rolle
spielen. Im gegebenen Kontext (der allerdings nur am Rande mit C zu tun
hatte) ist das vollkommen unrelevant.

Auf Ebene der Semantik kennt C ein sogenanntes 'break statement', das in
6.8.6.3 beschrieben wird.
Helmut Schellong
2014-06-27 11:51:56 UTC
Permalink
Post by Rainer Weikusat
Post by Juergen Ilse
Post by Claus Reibenstein
Post by Stefan Ram
Post by Juergen Ilse
Ich meinte das C-Statement "break"
»break;« ist eine Anweisung (a jump-statement, N1570 6.8.6p1).
»break« ist ein Schlüsselwort (a keyword, N1570 6.4.1p1).
Und »Korinthen« sind Rosinen aus der Rebsorte Korinthiaki.
Im Grunde genommen hatte er ja recht,
Nicht wirklich. 'break' ist in C ein Schluesselwort, eine bestimmte
Sorte von Token, die syntaktisch auch Bezeichner sein koennten, aber
nicht als Bezeichner benutzt werden duerfen, weil sie reserviert
sind. 'Schluesselworte' und 'Bezeichner' sind Dinge, die waehrend der
lexikalischen Analyse eines in C geschriebenen (Quell-)Textes eine Rolle
spielen. Im gegebenen Kontext (der allerdings nur am Rande mit C zu tun
hatte) ist das vollkommen unrelevant.
Auf Ebene der Semantik kennt C ein sogenanntes 'break statement', das in
6.8.6.3 beschrieben wird.
Man muß sicher nicht ``break;-Anweisung'' schreiben, um korrekt zu sein.

Natürliche Sprache ist nicht mathematisch exakt; da sind
oft Kompromisse vorhanden.
Oder aber man definiert und verwendet eine Erklär-Syntax, die
extra für diesen Zweck geschaffen wird/wurde.
(Excellent finde ich das im PEARL-Buch von Werum/Windauer.)

Wenn ich an die Leeranweisung ``;'' denke, dann ist das
Semikolon logisch ein Bestandteil einer Anweisung in C.
Es schließt Anweisungen ab.
Eine Trennfunktion ist dadurch gleichzeitig enthalten.

Wenn ``break-Anweisung'' geschrieben wird, ist das Semikolon
implizit in ``Anweisung'' enthalten: ``break-Anweisung: "break;"''.
--
Mit freundlichen Grüßen
Helmut Schellong ***@schellong.biz
www.schellong.de www.schellong.com www.schellong.biz
http://www.schellong.de/c.htm
Rainer Weikusat
2014-06-20 11:28:49 UTC
Permalink
Post by Volker Englisch
Post by Rainer Weikusat
[...]
Post by Volker Englisch
Post by Rainer Weikusat
if (sigflag) {
fputs(PASSTHRU_AUS, terminal);
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Post by Rainer Weikusat
signal(SIGINT, SIG_DFL);
raise(SIGITN);
}
Das hab ich jetzt an dieser Stelle noch eingefügt. Hoffe, das paßt.
Der Gedanke dabei war eigentlich, die Verarbeitungsschleife zu beenden,
den 'normalen' 'setzte alles zurueck'-Code auszufuehren (in dem
PASSTHRU_AUS enthalten war) und danach diesen Block einzufuegen.
Beispiel: User startet sehr langen Druckvorgang, merkt, dass es der
falsche war, will abbrechen und drückt CTRL-C. Damit sollte eigentlich
die Schleife sofort beendet werden...
Vollkommen race-frei ist das mit einem Flag nicht zu machen, dafuer
muesste man auf stdio verzichten und entweder setjmp/ longjmp oder
nichtblockiernede I/O in Kombination mit etwas wie 'pselect' benutzten,
womit man garantieren koennte, das das Signal tatsaechlich 'etwas
blockierndes' unterbricht, ein sogenannter 'lost wakeup' also nicht
vorkommen kann.

Die Frage ist allerdings, ob das die Muehe wert ist. Wenn man (mit einer
kleinen Korrektur) folgenden Code annimmt:

while (!sigflag && (x = fgetc(datei)) != EOF)
fputc(umwandlung(x), terminal)

kann hier ein Signal verlorengehen, falls es nach dem fgetc aber bevor
fputc blockiert (leicht vereinfacht) stattfindet. In allen anderen
Faellen wird die Schleife 'sofort' beendet, nachdem gegebenenfalls
vorher ein blockierender Systemaufruf (hatte ich schon mal erwaehnt, das
man unter Beschraenkung auf C dazu nur "Gib es auf und zuechte
stattdessen Radieschen!" sagen kann?) unterbrochen wurde. In diesem
Fall muesste man ^C solange wiederholen, bis es den gewuenschten Effekt
hat. Das koennte man einfach dokumentieren und es dabei belassen,
wenigstens insofern das Programm interaktiv benutzt wird.
Rainer Weikusat
2014-06-20 19:30:35 UTC
Permalink
Rainer Weikusat <***@mobileactivedefense.com> writes:

[...]
Post by Rainer Weikusat
while (!sigflag && (x = fgetc(datei)) != EOF)
fputc(umwandlung(x), terminal)
kann hier ein Signal verlorengehen, falls es nach dem fgetc aber bevor
fputc blockiert (leicht vereinfacht) stattfindet.
Der Vollstaendigkeit halber sei erwaehnt, dass sich ein solches Fenster
natuerlich auch nach zwischen dem Ende des !sigflag-Tests und fgetc bzw
dem darunterliegenden, blockierenden read-Aufruf befindet.
Volker Englisch
2014-06-22 16:13:54 UTC
Permalink
Post by Rainer Weikusat
Post by Volker Englisch
Beispiel: User startet sehr langen Druckvorgang, merkt, dass es der
falsche war, will abbrechen und drückt CTRL-C. Damit sollte eigentlich
die Schleife sofort beendet werden...
Vollkommen race-frei ist das mit einem Flag nicht zu machen, dafuer
muesste man auf stdio verzichten und entweder setjmp/ longjmp oder
nichtblockiernede I/O in Kombination mit etwas wie 'pselect' benutzten,
womit man garantieren koennte, das das Signal tatsaechlich 'etwas
blockierndes' unterbricht, ein sogenannter 'lost wakeup' also nicht
vorkommen kann.
Okay... Das sind alles Sachen, die mir erst mal gar nichts sagen. Ich
werde mich aber gelegentlich mal einlesen, versprochen.
Post by Rainer Weikusat
Die Frage ist allerdings, ob das die Muehe wert ist. Wenn man (mit einer
while (!sigflag && (x = fgetc(datei)) != EOF)
fputc(umwandlung(x), terminal)
kann hier ein Signal verlorengehen, falls es nach dem fgetc aber bevor
fputc blockiert (leicht vereinfacht) stattfindet. In allen anderen
Faellen wird die Schleife 'sofort' beendet,
Bei drei verschachtelten Klammerebenen ist mein abstraktes Denkvermögen
schon ziemlich gefordert, aber ich glaube zu begreifen, was es bedeuten
soll. Ich werde es jetzt mal so umsetzen und dann mal in der Praxis
testen.

Danke Dir nochmal für die viele Geduld!

V*
Loading...