Anfaengerfrage Signalhandling

16/06/2014 - 18:40 von blackavar | Report spam
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" );
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" );
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 );
}
 

Lesen sie die antworten

#1 Rainer Weikusat
16/06/2014 - 22:12 | Warnen spam
(Volker Englisch) writes:
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*



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.



#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.

[...]


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

int main ( int argc, char *argv[] )
{
int x;
FILE *terminal;
terminal = fopen ( "/dev/tty", "w" );
if ( terminal == NULL )
{
printf ( "Kann Terminal nicht öffnen" );
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.


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" );
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.

Ähnliche fragen