Ausdrücke ohne Wert in C (Ausdrücke ohne Wert in C), Lektion, Seite 722929
https://www.purl.org/stefan_ram/pub/ohne_wert_c (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C-Kurs

Ausdrücke ohne Wert in C  (Reine Wirkfunktionen)

Diese Lektion wird gerade überarbeitet. Daher kann es sein, daß sie im derzeitigen Zustand noch Mängel enthält.

»abort«

Die Auswertung des Ausdrucks »abort()« beendet das laufende Programm.

abort [Dokumentation]
Synopse
#include <stdlib.h>
_Noreturn void abort( void );
Wirkung: beendet das laufende Programm
mit einer Fehlermeldung.

Während die Auswertung des Aufrufausdruck »putchar( 65 )« einen Wert und  eine Wirkung hat, hat die Auswertung des Aufrufausdruck »abort()" keinen  Wert, sondern nur eine Wirkung. Wir sagen dazu auch, daß »abort()« ein reiner Wirkausdruck  sei.

Um dies zu kennzeichnen wird in der Synopse das Wort "void" (leer, nichtig) dort vor den Namen der Funktion geschrieben, wo sonst der Rückgabetyp steht.

Das folgende Beispiel zeigt den Aufruf dieser Standardfunktion mit Hilfe einer Auswertungsanweisung. void -Wirkfunktionen passen gut zur Auswertungsanweisung, da sie wegen der Wirkung ihrer Auswertung verwendet werden.

main.c

#include <stdlib.h> /* abort */

int main( void ){ abort(); }

(Die Prozedur "abort" soll hier aber nicht zur Benutzung empfohlen werden. Sie wird nun deshalb hier verwendet, weil sie ein einfaches Beispiel einer reinen Wirkfunktion ist.)

Der Funktionsspezifizierer »_Noreturn«

Die Synopse für »abort« wurde oben etwas verkürzt, indem das in dieser Lektion unwichtige »_Noreturn« weggelassen wurde. In diesem Abschnitt soll das »_Noreturn« nun aber doch noch kurz erklärt werden.

abort [Dokumentation]
Synopse
#include <stdlib.h>
_Noreturn void abort( void );
Wirkung: beendet das laufende Programm
mit einer Fehlermeldung.

Der Funktionsspezifizierer »_Noreturn« (aus »<stdnoreturn.h>«) teilt uns mit, daß diese Funktion nach ihrem Aufruf die Kontrolle über den Computer nicht  an den Aufrufer zurückgibt. Die Kennzeichnung mit »_Noreturn« ist für reine Wirkfunktionen nicht  typisch. Die meisten reinen Wirkfunktionen geben  die Kontrolle zurück. Wir werden in dieser Lektion auch noch ein Beispiel einer reinen Wirkfunktion sehen, welche zu ihrem Aufrufer zurückkehrt (das heißt: die Kontrolle an ihren Aufrufer zurückgibt).

»srand«

srand [Dokumentation] (vereinfacht)
Synopse
#include <stdlib.h>
void srand( int w );
Wirkung: Der Zufallszahlengenerator
wird auf den Zustandswert w eingestellt.

Die Auswertung des Ausdrucks »rand()« liefert eine Zufallszahl, welche von einem Zufallszahlengenerator erzeugt wird. Diese Zufallszahl wird durch den Zustands des Zufallszahlengenerators bestimmt. Der Zustand des Zufallszahlengenerators ist eine Zahl.

main.c

#include <stdio.h>
#include <stdlib.h>

int main( void )
{ srand( 2 ); printf( "%d\n", rand() );
srand( 3 ); printf( "%d\n", rand() );
srand( 2 ); printf( "%d\n", rand() );
srand( 3 ); printf( "%d\n", rand() ); }

stdout (Ausgabe ist implementationsspezifisch)
45
48
45
48

Dies bedeutet, daß der Zufallszahlengenerator im gleichen Zustand auch die gleiche Zahl liefert. Es heißt aber nicht, daß die gelieferte Zufallszahl dem Zustand gleich ist.

main.c

#include <stdio.h>
#include <stdlib.h>

int main( void )
{ srand( 1 ); printf( "%d\n", rand() );
srand( 1 ); printf( "%d\n", rand() ); }

stdout (Ausgabe ist implementationsspezifisch)
41
41

Die Auswertung des Ausdrucks »rand()« verändert den Zustand nachdem die zu liefernde Zufallszahl festgelegt wurde. Dies bedeutet, daß sich beim nächsten Aufruf von »rand()« eine andere Zufallszahl ergeben kann.

 .--------.      .-------.      .-------.       .--------.      .--------.
( Argument )---->| srand |---->( Zustand )<---->| rand() |---->( Ergebnis )
'--------' '-------' '-------' '--------' '--------'
main.c

#include <stdio.h>
#include <stdlib.h>

int main( void )
{ srand( 2 ); printf( "%d ", rand() ); printf( "%d\n", rand() );
srand( 3 ); printf( "%d ", rand() ); printf( "%d\n", rand() );
srand( 2 ); printf( "%d ", rand() ); printf( "%d\n", rand() );
srand( 3 ); printf( "%d ", rand() ); printf( "%d\n", rand() ); }

stdout (Ausgabe ist implementationsspezifisch)
45 29216
48 7196
45 29216
48 7196

Wir sehen hier zum ersten Mal das wichtige Prinzip, daß es einen von mehreren Funktionen geteilten Zustand  gibt, auf den von außen nicht direkt zugegriffen werden kann (Kapselung, privater Zustand). Wir haben eine Wirkfunktion, welche die Veränderung dieses Zustandes erlaubt, und eine Wertfunktion, deren Verhalten von diesem Zustand beeinflußt wird. (Unter einer Wertfunktion  verstehen wir eine Funktion, deren Aufruf einen anderen Typ als »void« hat. Hat die Auswertung des Aufrufs eine Funktion laut Dokumentation eine Wirkung, so nennen wir jene Funktion ein Wirkfunktion.)

Der Zustand kann mit »srand« festgelegt werden, aber es gibt keine Möglichkeit, ihn direkt auszulesen.

Typische Aufrufmuster

Ausdrücke ohne Wert können nicht als Argumente oder Operanden verwendet werden.

Matrix

Beispiel Wertverwendung Wirkungsrealisierung

kein Wert und keine Wirkung - - ...; (keine Wirkung)

Wirkung und kein Wert abort - ...;

Wert und keine Wirkung cos printf( ... ); ...; (keine Wirkung)
(oder als Operand oder Argument)

Wert und Wirkung putchar printf( ... ); ...;
(oder als Operand oder Argument)

Übungsfragen
Übungsfragen und Übungsaufgaben

Eine Wirkfunktion ist eine Funktion, die laut Dokumentation eine Wirkung hat. (Genauer gesagt: Die Auswertung ihres Aufrufs (welcher ein Ausdruck ist), hat laut Dokumentation eine Wirkung.)

Handelt es sich bei der Funktion »srand« um eine Wirkfunktion ?

Ein Wirkausdruck ist ein Ausdruck, dessen Auswertung eine Wirkung hat.

Ein Wertausdruck ist ein Ausdruck, dessen Auswertung einen Wert ergibt.

?    Wirk- oder Wertaufrufausdruck?
Handelt es sich bei den folgenden Aufrufausdrücken um Wirk- oder Wertausdrücke? Welche Wirkung beziehungsweise welchen Wert haben sie gegebenenfalls?
  • »rand()«
  • »abort()«

?   Übungsfrage

?    »srand«
Ergibt die Auswertung des Ausdrucks »srand( 0 )« einen Wert?
Hat die Auswertung des Ausdrucks »srand( 0 )« eine Wirkung?
/    »srand«
Schreiben Sie ein Programm, in dem ein Wert des Ausdrucks »rand()« ausgegeben wird. Welcher Wert wird ausgegeben, wenn das Programm dann so geändert wird, daß einmal »srand( 10 )« und einmal »srand( 1 )« vor der Ausgabe von »rand()«ausgewertet wird? (Das Programm soll in diesen beiden Fällen immer nur einen Aufruf von »srand« und dann einen Aufruf von »rand« enthalten.)

.----------------------------------------------------------------------------------------.
| Welt |
| (Speicher, Uhr) |
| |
| |
| |
'----------------------------------------------------------------------------------------'
^ ^ ^
| | |
| v v
.----------------------. .----------------------. .----------------------.
| Auswertung von | | Auswertung von | | Auswertung von |
| ::std::srand( 10 ) | | ::std::rand() | | ::std::rand() |
| | | | | |
| | | | | |
| | | | | |
'----------------------' '----------------------' '----------------------'

Zeit --->

Übungsaufgaben

/   Wertfunktion time

Der Aufruf von <time.h> »time« liefert eine Zahl, die sich im Laufe der Zeit verändert, meist wird jede Sekunde um 1 hochgezählt.

time [Synopse, für den Kurs etwas vereinfacht und daher nicht ganz korrekt]
#include <time.h> 
int time( int );

?    »time«
Hat der Ausdruck »time( 0 )« einen Wert?
Hat die Auswertung des Ausdrucks »time( 0 )« eine Wirkung?

Tip zum schnellen Lernen Versuchen Sie jetzt nicht, zu verstehen, was die »0« in »time( 0 )« bedeutet. Dies ist derzeit noch nicht wichtig! Vorläufig reicht es sich zu merken, daß bis auf weiteres als Argument immer »0« verwendet werden muß.

main.c
#include <stdio.h> 
#include <time.h>
int main( void ) 
{ printf( "%d\n", time( 0 )); 
printf( "%d\n", time( 0 )); }

/    Zufallszahlen verbessern
Kombinieren Sie den Ausdruck »time( 0 )« mit der Wirkfunktion »srand«, um zu erreichen, daß der Pseudozufallszahlengenerator durch die Uhrzeit beim Start des Programmes beeinflußt wird. Bei jedem Programmstart sollte also eine andere Funktion erscheinen.
Geben Sie danach eine mit »rand()« ermittelte Zufallszahl aus, um den Effekt sichtbar zu machen. In »time( 0 )« sollte die »0« so belassen und nicht durch etwas anderes ersetzt werden!
/    Zufallszahlen weiter verbessern
Nach Lösung der vorigen Aufgabe sind die ausgegebenen Zufallszahlen von zwei aufeinanderfolgenden Programmläufen unter manchen Implementationen einander ähnlich. Ändern Sie das Programm so ab, daß die ausgegebene Zufallszahl meistens nicht mehr der vom vorangehenden Programmlauf ähnelt.

Mit den folgenden Übungsaufgaben soll das selbständige Schreiben von Programmen an Hand der Dokumentation geübt werden.

Wenn es sich bei der aufzurufenden Funktion um eine Wertfunktion handelt, soll hier Wert ausgegeben werden.

Wenn die aufzurufende Funktion keinen Wert liefert, soll sie in einer Auswertungsanweisung aufgerufen werden.

Aufruf der Funktion »terminate«
terminate

Diese Übungsaufgabe ist noch nicht verwendbar! Sie muß erst noch überarbeitet werden.

#include <exception>
void terminate();
Abbruch eines Programms.
Die Funktion »terminate« bewirkt (wenn nichts anderes eingestellt wurde) meist den sofortigen Abbruch eines Programms. Das ist meist nicht besonders nützlich. Diese Funktion wird hier vor allem deswegen behandelt, weil ihre Verwendung besonders einfach ist! Nützlichere Funktionen werden später vorgestellt werden.
Übungsaufgabe: Rufen Sie die Funktion »terminate« in einem Programm auf!
Hinweis: Wenn das Programm richtig geschrieben wurde, dann sollte die C -Implementation keinen Fehler in dem Programm melden. Beim Start des Programms sollte allerdings auch nicht viel von dem Programm zu sehen sein, da es sofort abgebrochen wird. (Manchmal erscheint dabei eine kurze Meldung, die besagt, daß das Programm abgebrochen wurde.) Hinweis: Verwenden Sie das vorherige Beispielprogramm zu »getchar« als Ausgangspunkt und ändern Sie es an zwei Stellen ab.
Aufruf der Funktion »round«
round

#include <math.h>

double round( double x );

Diese Funktion rundet ihren Argumentwert in Richtung der nächsten ganzen Zahl.
Übungsaufgabe: Rufen Sie die Funktion »round« in einem Programm auf!

Reine Wirkfunktionen

Wir hatten schon gesehen, daß einige Funktionen, wie etwa »rand()« mit »int« vor ihrem Namen (z.B. »int rand«) dokumentiert sind. Das bedeutet, daß die Auswertung des Aufrufausdrucks »rand()« einen Wert vom Typ »int« ergibt. Solch eine Auswertung, die einen Wert liefert, wird hier auch als Wertauswertung  bezeichnet. Entsprechend kann »rand()« als Wertaufruf, als Wertausdruck, als Wertoperation  oder als Wertfunktion  angesehen werden (das ist aber deswegen nicht alles dasselbe, es kommt auf den Zusammenhang an).

Wir hatten schon gesehen, daß in der Dokumentation einiger Funktionen, wie etwa in der von »abort()«, ein bestimmte Wirkung  beschrieben ist, nämlich in diesem Fall den Abbruch des laufenden Programms. Eine Funktion, deren Aufruf laut Dokumentation solch eine Wirkung hat, wird hier auch Wirkfunktion  genannt.

Wirkung  bedeutet dabei, daß laut Dokumentation durch den Aufruf etwas verändert  wird. Eine Wirkung muß nicht unbedingt sofort beobachtbar sein, sie kann sich auch versteckt im Inneren des Computers abspielen, es genügt, wenn sie in der Dokumentation beschrieben ist. Jedoch hat man die Festlegung eines Ergebnisses  vom Begriff der Wirkung ausgenommen, deswegen gilt eine Funktion, die nur ein Ergebnis liefert, aber sonst laut ihrer Dokumentation nichts anderes macht (d.h., verändert) nicht als eine Wirkfunktion.

Das folgende Beispiel zeigt den Aufruf der Wertfunktion  »rand()«. Der ermittelte Wert ist in diesem Fall 41.

main.c

#include <stdio.h>

int main( void ){ printf( "%d\n", rand() ); }

stdout
41

Das folgende Beispiel zeigt den Aufruf der Wirkfunktion »abort()«. Die Wirkung besteht im Abbruch des Programms, oft zusammen mit der Ausgabe einer Fehlermeldung.

Es zeigt sich aber, daß nicht alle  Aufrufvorgänge einen Wert festlegen.

main.c

#include <stdio.h>
#include <stdlib.h>

int main( void ){ printf( "%d\n", abort() ); }

Konsole
(Fehlermeldung des Compilers)

Eine solche Funktion, die keine Wertfunktion ist, wird entsprechend ihrer Dokumentation auch manchmal als void -Funktion bezeichnet.

Wir hatten schon gesehen, daß in der Dokumentation einiger Funktionen, wie etwa in der von »abort()«, ein bestimmte Wirkung  beschrieben ist, nämlich in diesem Fall den Abbruch des laufenden Programms. Eine Funktion, deren Aufruf laut Dokumentation solch eine Wirkung hat, wird hier auch Wirkfunktion  genannt.

Das folgende Beispiel zeigt den Aufruf der Wirkfunktion »abort()«. Die Wirkung besteht im Abbruch des Programms, oft zusammen mit der Ausgabe einer Fehlermeldung.

main.c

#include <stdlib.h>

int main( void ){ abort(); }

Konsole
(Abbruch der Programmausführung)
abort
#include <stdlib.h>
void abort( void );
Abbruch eines Programms.

Das »void« in der Dokumentation von »abort« stellt klar, daß der Aufruf dieser Funktion keinen Wert hat.

Dokumentation von »abort« (gekürzt und überarbeitet)
The abort function
Synopsis
#include <stdlib.h>
void abort( void );
causes abnormal program termination

Wir nennen den Typ vor dem Namen einer Funktion auch den Ergebnistyp  dieser Funktion.

Ausnahmsweise gibt »void« aber gar nicht den Typ eines Wertes an, wie ein Typ sonst, sondern liefert vielmehr die Information, daß es gar keinen Wert gibt  (und ohne  Wert gibt es natürlich auch keinen Typ  des Werts). Weil es keinen Wert gibt, entfällt die Typangabe (engl. “void ” = [hier] deutsch „entfällt“). Damit ist »void« kein Typ eines Wertes, wie die Bezeichnung „Typ“ nahelegt. Es ist jedoch als Ergebnistyp in der Dokumentation einer Funktion zulässig, um zu kennzeichnen, daß ein Aufruf dieser Funktion nicht dort verwendet werden kann, wo ein Wert erwartet wird. Man kann hier genauer von einem Metatyp  sprechen, um auszudrücken, daß dies kein möglicher Typ eines Wertes ist, sondern die Information, daß es keinen Wert gibt.

Der Typ vor dem Namen einer Funktion ist also genau genommen der Ergebnismetatyp  dieser Funktion.

Wenn für eine Funktion in ihrer Dokumentation Wirkungen beschrieben sind, die über die Festlegung eines Rückgabewertes hinausgehen, dann nennen wir diese Funktion also eine „Wirkfunktion“.

Wirkungen (engl. “effects ”) werden manchmal auch als Nebenwirkungen (engl. “side effects ”) bezeichnet, was aber eine unpassende Bezeichnung ist, da Nebenwirkungen störend oder nebensächlich sind, während Wirkungen eine meist erwünschte Hauptsache sind. Noch schlimmer ist das Wort „Seiteneffekte“, das lediglich ein Fehler bei der Übersetzung aus dem Englischen “side effects ” (dt. „Nebenwirkungen“) ist.

Wert von »rand« [Kompaßdiagramm]
.----------------------------.
| rand() | Wert
| |------------------->
| | Pseudozufallszahl
'----------------------------'
Wirkung von »abort« [Kompaßdiagramm]
.----------------------------.
| abort() |
| |
| |
'----------------------------'
Wirkung | Programmabbruch
V

Wertwirkfunktionen

Wirkungen einer Funktion und ein Ergebniswert einer Funktion müssen nicht einander ausschließen. Wenn eine Funktion beides hat, dann kann man sie auch als Wertwirkfunktion  bezeichnen (oder als „Wirkwertfunktion“), oder auch – wahlweise – nur als „Wirkfunktion“ oder nur als „Wertfunktion“, denn sie ist ja dann beides.

Aufrufe Rahmen

... ;

abort()

printf( "%s\n", ... );

rand()

printf( "%d\n", ... );

sin( 2. )

printf( "%g\n", ... );

UE A: Aufrufe den Rahmen zuordnen!

Matrix

Wertverwendung Wirkungsrealisierung

kein Wert und keine Wirkung

Wert und keine Wirkung als Argument/Operand
oder in printf

kein Wert aber Wirkung vor Semikolon aufrufen

Wert und Wirkung als Argument/Operand vor Semikolon aufrufen
oder in printf

Übungsfragen und Übungsaufgaben

Handelt es sich bei der Funktion »getchar« um eine Wirkfunktion ?

?    Wirk- oder Wertaufrufausdruck?
Handelt es sich bei den folgenden Aufrufausdrücken um Wirk- oder Wertaufrufausdrücke?
  • »rand()«
  • »abort()«
?    Wirkung von Auswertungen
Welche Wirkung  hat die Auswertung der folgenden Aufrufausdrücke jeweils (falls überhaupt)?
  • »rand()«
  • »abort()«
?    Werte von Auswertungen
Welche Werte  ergibt die Auswertung der folgenden Aufrufe jeweils (falls überhaupt)?
  • »rand()«
  • »abort()«
Aufruf weiterer Funktionen
tmpfile
#include <stdio.h>
tmpfile( void );
clock()
#include <time.h>
clock( void );

Ausdrücke ohne Wert in C

abort: Ausdrücke ohne Wert, Aufruf ist nicht im Ausdruckrahmen möglich

srand( 2 );

abort();

Aufruf der Funktion »terminate«
terminate
#include <exception>
void terminate( void );
Abbruch eines Programms.
Die Funktion »terminate« bewirkt (wenn nichts anderes eingestellt wurde) meist den sofortigen Abbruch eines Programms. Das ist meist nicht besonders nützlich. Diese Funktion wird hier vor allem deswegen behandelt, weil ihre Verwendung besonders einfach ist! Nützlichere Funktionen werden später vorgestellt werden.
Welche Include-Direktive  wird am Anfang des Programms benötigt, wenn der Bezeichner »terminate« darin verwendet werden soll?
Übungsaufgabe: Rufen Sie die Funktion »terminate« in einem C++ -Programm auf!
Hinweis: Wenn das Programm richtig geschrieben wurde, dann sollte die C++ -Implementation keinen Fehler in dem Programm melden. Beim Start des Programms sollte allerdings auch nicht viel von dem Programm zu sehen sein, da es sofort abgebrochen wird. (Manchmal erscheint dabei eine kurze Meldung, die besagt, daß das Programm abgebrochen wurde.) Hinweis: Verwenden Sie das vorherige Beispielprogramm zu »getchar« als Ausgangspunkt und ändern Sie es an zwei Stellen ab.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram722929 stefan_ram:722929 Ausdrücke ohne Wert in C Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd722929, slrprddef722929, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/ohne_wert_c