Reine Wirkfunktionen in C++ (Reine Wirkfunktionen in C++), Lektion, Seite 723469
https://www.purl.org/stefan_ram/pub/reine_wirkfunktionen_c++ (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C++-Kurs

Reine Wirkfunktionen in C++ 

Wir hatten zuerst Funktionen kennengelernt, bei denen die Auswertung eines Aufrufs einen Wert ergibt (»rand«).

Dann hatten wir Funktionen kennengelernt, bei denen die Auswertung eines Aufrufs einen Wert ergibt und eine Wirkung hat (»putchar«).

Nun behandeln wir noch Funktionen, bei denen die Auswertung eines Aufrufs nur  eine Wirkung hat.

Reine Wirkfunktionen

Wir hatten schon gesehen, daß einige Funktionen, wie etwa »::std::rand()« mit »int« vor ihrem Namen (z.B. »int rand«) dokumentiert sind. Das bedeutet, daß die Auswertung des Aufrufausdrucks »::std::rand()« einen Wert vom Typ »int« ergibt. Solch eine Auswertung, die einen Wert liefert, wird hier auch als Wertauswertung  bezeichnet. Entsprechend kann »::std::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 »::std::putchar()«, ein bestimmte Wirkung  beschrieben ist, nämlich in diesem Fall die Ausgabe eines Zeichen. 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  »::std::rand()«. Der ermittelte Wert ist in diesem Fall 41.

main.cpp

#include <iostream> // ::std::cout
#include <ostream> // <<
#include <cstdlib> // ::std::rand
#include <string> // ""s

using namespace ::std::literals;

int main()
{ ::std::cout << ::std::rand() << "\n"s; }

::std::cout
41

Das folgende Beispiel zeigt den Aufruf der Wirkfunktion »::std::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.cpp

#include <iostream> // ::std::cout
#include <ostream> // <<
#include <cstdlib> // ::std::abort
#include <string> // ""s

using namespace ::std::literals;

int main()
{ ::std::cout << ::std::abort() << "\n"s; }

Konsole
Error: binary '<<' does not take a right-hand operand of type 'void'
Aussprachehinweis
abort əˈ bɔɚt

Eine solche Wirkfunktion, die keine Wertfunktion ist, wird entsprechend ihrer Dokumentation auch manchmal als void -Funktion bezeichnet. Wir nennen sie auch eine reine Wirkfunktion.

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

main.cpp

#include <cstdlib> /* ::std::abort */

int main(){ ::std::abort(); }

Konsole
(Abbruch der Programmausführung)
::std::abort

#include <cstdlib>

void abort();

Bricht den Prozeß ab.

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

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 »::std::rand« [Kompaßdiagramm]
.----------------------------.
| ::std::rand() | Wert
| |------------------->
| | Pseudozufallszahl
'----------------------------'
Wirkung von »::std::abort« [Kompaßdiagramm]
.----------------------------.
| ::std::abort() |
| |
| |
'----------------------------'
Wirkung | Programmabbruch
V
Wert und Wirkung der Auswertung von »::std::putchar( 65 )« [Kompaßdiagramm]
.----------------------------.
| ::std::putchar( 65 ) | Wert
| |-------------------> 65
| |
'----------------------------'
Wirkung |
V
Ausgabe eines A

Aufrufe von Wirkfunktionen ohne Wert (Aufrufschema)

Eine Wirkfunktion ohne Wert  sollte normalerweise (bis auf weiteres) immer innerhalb eines Wirkaufrufrahmens  aufgerufen werden, wenn die dokumentierte Wirkung eintreten soll.

Das folgende Beispiel zeigt, wie man eine Wirkfunktion ohne Wert normalerweise aufrufen sollte, damit die für sie dokumentierte Wirkung eintritt.

Wir können eine Auswertungsanweisung an der Stelle der Ausgabeanweisung in den bisherigen Ausdruckrahmen einsetzen. (Im speziellen Falle des folgenden Programmes können dann noch einige include-Zeilen und eine using-Zeile entfallen.)

main.cpp

#include <cstdlib> /* ::std::abort */

int main(){ ::std::abort(); }

Konsole
(Abbruch der Programmausführung)

Das folgende Beispiel zeigt, daß man eine Wirkfunktion ohne Wert normalerweise nicht  in einem Ausdruckrahmen aufrufen sollte, weil dieser einen Wert erwartet.

main.cpp

#include <iostream> // ::std::cout
#include <ostream> // <<
#include <cstdlib> // ::std::abort
#include <string> // ""s

using namespace ::std::literals;

int main()
{ ::std::cout << ::std::abort() << "\n"s; }

Konsole
Error: binary '<<' does not take a right-hand operand of type 'void'

Es ist mit diesen Hinweisen hoffentlich auch verständlich geworden, daß ein Programmierer immer wissen muß, ob eine Funktion einen Wert und/oder eine Wirkung hat, denn nur dann kann er sie richtig aufrufen.

Die beiden vorgestellten Aufrufschema sollte man sich gut einprägen:

Der Aufruf einer Wertfunktion  steht im allgemeinen im Ausdruckrahmen, der Aufruf einer Wirkfunktion  steht im allgemeinen im Aufrufrahmen. (Diese Regel gilt nur für den Anfang, später wird erklärt werden, daß es auch noch andere Möglichkeiten gibt.)

void -Wirkfunktionen passen gut zur Auswertungsanweisung, da sie wegen der Wirkung ihrer Auswertung verwendet werden.

main.cpp

#include <cstdlib> /* ::std::abort */

int main(){ ::std::abort(); }

Wertwirkfunktionen

Wirkungen einer Funktion und ein Ergebniswert einer Funktion müssen nicht einander ausschließen. Wenn eine Funktion beides hat (wie im Falle von »::std::putchar«), 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.

Matrix

Beispiel Wertverwendung Wirkungsrealisierung

kein Wert und keine Wirkung - ...;

Wert und keine Wirkung cos ::std::cout << ... << "\n"s; -
(oder als Operand oder Argument)

Wert und Wirkung putchar ::std::cout << ... << "\n"s; ...;
(oder als Operand oder Argument)

Wirkung und kein Wert abort - ...;

Übungsfragen und Übungsaufgaben

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?
Und was ist gegebenenfalls die Wirkung beziehungsweise der Wert?
  • »::std::rand()«
  • »::std::abort()«

?   Anweisungen

Welche der beiden folgenden Anweisungen sind sinnvoll (d.h.: Welche der beiden folgenden Anweisungen können ohne Fehlermeldung übersetzt werden)?

Anweisungen
o »::std::abort();«
o »::std::cout << ::std::abort()<< "\n"s;«

?   Übungsfragen ⃗

Übungsaufgaben

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

Aufruf der Funktion »::std::terminate«

Für diese und die nächste Aufgabe soll die folgende Regel beachtet werden:

Dokumentation

#include <exception>

void terminate();

Abbruch eines Programms.

Die Funktion »::std::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 »::std::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 »::std::getchar« als Ausgangspunkt und ändern Sie es an zwei Stellen ab.

Aufruf der Funktion »::std::round«

Auch hier soll wieder die folgende Regel beachtet werden:

Dokumentation

#include <cmath>

double ::std::round( double x );

Diese Funktion rundet ihren Argumentwert in Richtung der nächsten ganzen Zahl.

Übungsaufgabe: Rufen Sie die Funktion »::std::round« in einem C++ -Programm auf!

Z Ausgabe eines eingelesenen Zeichen

Schreiben Sie ein Programm, das ein mit »::std::getchar« eingelesenes Zeichen mit »::std::putchar« wieder ausgibt.

Dokumentation

#include <cstdio>

int ::std::putchar( int c );

Wirkung: schreibt das Zeichen mit der Kennzahl c.
Dokumentation

#include <cstdio>

int ::std::getchar();

Einlesen eines Zeichens von der Konsole.
Wert: Die Kennzahl des nächsten von der Konsole eingelesenen Zeichens

Diese Aufgabe sollte möglichst mit den bisher im Kurs behandelten Mitteln gelöst werden.

Während der Auswertung eines Aufrufs des Funktion »::std::getchar« wartet der Computer auf eine Eingabe in der Konsole (normalerweise ist dies der Bereich, in dem auch Ausgaben des Programms erscheinen.) Um ein bestimmtes Zeichen einzugeben, muß dann zuerst dieses Zeichen eingegeben werden (normalerweise über die Tastatur) und dann zur Bestätigung die Eingabetaste betätigt werden.

ZZ Ausgabe des Nachfolgers eines eingelesenen Zeichen

Schreiben Sie ein Programm, das den Nachfolger einer mit »::std::getchar« eingelesenen Ziffer (0-8) mit »::std::putchar« wieder ausgibt. (Der Nachfolger von »2« ist beispielsweise »3«. Die Zeichenkennzahl des Nachfolgers einer Ziffer ist um 1 größer als die Kennzahl der Ziffer).

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 stefanram723469 stefan_ram:723469 Reine Wirkfunktionen in C++ Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd723469, slrprddef723469, 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/reine_wirkfunktionen_c++