Funktionen variabler Arität in C (Funktionen variabler Arität in C), Information, Seite 724207
https://www.purl.org/stefan_ram/pub/varargs_c (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C-Kurs

Funktionen variabler Arität in C 

Die Ausgabeanweisung ohne  Formatspezifizierer

Syntax Der Quelltext »printf( "\n" );« stellt ebenfalls eine Ausgabeanweisung  dar.

Semantik Bei der Ausführung der Ausgabeanweisung »printf( "\n" );« wird ein Zeilenende ausgegeben.

Ausgabeanweisungen

Anweisung
.------. .-. .----------------------. .-. .----------. .-. .-.
---->( printf )--->( ( )--->| Zeichenfolgenliteral |--->( , )--->| Ausdruck |--->( ) )--->( ; )--->
'------' '-' '----------------------' '-' '----------' '-' '-'

Anweisung
.------. .-. .----------------------. .-. .-.
---->( printf )--->( ( )--->| Zeichenfolgenliteral |--->( ) )--->( ; )--->
'------' '-' '----------------------' '-' '-'

main.c

#include <stdio.h>

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

stdout
1
2
1

2

Variable-Argumente-Funktionen

Die Funktion »printf« gehört zu einer speziellen Art von Funktionen, bei denen die maximale Anzahl der Argumente nicht festgelegt ist. »printf« muß mit mindestens einem Argument aufgerufen werden. Dieses erste Argument muß den Typ »char *« haben. Die Möglichkeit, weitere Argumente beliebigen Typs anzugeben, wird in der Dokumentation durch eine Ellipse »...« gekennzeichnet.

Auszug aus der Dokumentation von »printf« (nach N1570, vereinfacht, überarbeitet und übersetzt)
7.21.7.4 Die Funktion »printf«
Synopse
#include <stdio.h>
int printf( char * format, ... );

Variante der Ausgabeanweisung ohne Zeilenende

Es gibt eine Variante der Ausgabeanweisung, bei der das »\n« weggelassen wird. Dann wird die Zeile nicht abgeschlossen. Dies ist manchmal nützlich, wenn die Ausgabe in eine Zeile später noch fortgesetzt werden soll.

eine abstrakte Ausgabeanweisung ohne Zeilenende (hier neu)
printf( "%", );
main.c

#include <stdio.h>

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

stdout
412

Ein einzelnes Zeilenende kann dann mit einer Ausgabeanweisung ohne Formatspezifizierer ausgegeben werden.

Eine Ausgabeanweisung ohne Formatspezifizierer
printf( "\n" );
main.c

#include <stdio.h>

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

stdout
4
12

Das voranstehende Programm hat dasselbe Verhalten wie das folgende.

main.c

#include <stdio.h>

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

stdout
4
12

Der ordentliche Abschluß einer ausgegebenen Zeile

Wenn ein Programm überhaupt  etwas als Text ausgibt, dann sollte die letzte Ausgabe des Programms ein Zeilenende sein, da jede  Zeile mit einem Zeilenende abgeschlossen werden sollte.

Zitat*
7.21.2 Streams
2 A text stream is an ordered sequence of characters composed into lines, each line consisting of zero or more characters plus a terminating new-line character. Whether the last line requires a terminating new-line character is implementation-defined.

Da es von der Implementation abhängt, ob ein Zeilende als Abschluß der letzten Zeile einer Textausgabe benötigt  wird, wird man nur dann allen  Implementationen gerecht, wenn man die letzte ausgegebene Zeile immer  mit einem Zeilenende abschließt.

Übungsfragen

?   Übungsfrage

Welche Ausgabe erzeugt das folgende Programm?

(84: T, 85: U, 86: V, 87: W, 88: X)

main.c

#include <stdio.h>

int main( void )
{ printf( "", putchar( 86 )); }

?   Übungsfrage

Welche Ausgabe erzeugt das folgende Programm?

(84: T, 85: U, 86: V, 87: W, 88: X)

main.c

#include <stdio.h>

int main( void )
{ printf( "W", putchar( 86 )); }

?   Sprechweisen

„In dem folgenden Programm wird ein Wert von »printf« __________, der von »rand« __________ wird.“

main.c

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

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

stdout
41

?   Zeilen angeben

Wie viele Zeilen gibt das folgende Programm aus, und was steht auf diesen Zeilen?

main.c

#include <stdio.h>

int main( void )
{ printf( "%d", 5 ); printf( "%d", 2 );
printf( "%d\n", 2 ); printf( "%d\n", 4 ); }

?   Zeilen angeben (1)

Wie viele Zeilen gibt das folgende Programm aus, und was steht auf diesen Zeilen?

main.c

#include <stdio.h>

int main( void )
{ printf( "522\n4\n" ); }

Auswertung mit bekannter Reihenfolge (1)

In diesem Beispiel zeigen wir die einzelnen Operationen, die während der Auswertung des Ausdrucks »putchar( 1 + putchar( 71 ))« ausgeführt werden. (Zur Vereinfachung behandeln wir hier nur diesen Ausdruck, dessen Ausgabe »GH« ausgibt, und nicht auch noch die printf-Anweisung, welche dann noch »72« ausgibt.)

main.c

#include <stdio.h>

int main( void )
{ printf( "%d\n", putchar( 1 + putchar( 71 ))); }

stdout
GH72
Der Beispielausdruck
putchar( 1 + putchar( 71 ))

Bevor die erste Funktion »putchar« ausgeführt werden kann, muß zunächst der Wert des Argumentausdrucks »1 + putchar( 71 )« ermittelt werden.

Um den Wert der Summe »1 + putchar( 71 )« ermitteln zu können, muß zunächst der Wert des Summanden »putchar( 71 )« ermittelt werden.

So ergibt sich die Reihenfolge der folgenden drei Operationen

Operation 0 »putchar( 71 )«

Funktionsoperation »putchar( 71 )«
»putchar( 71 )« → »71« ↓ Ausgabe von »G«

Die Operation »putchar( 71 )« entspricht der Auswertung des Ausdrucks »putchar( 71 )«, sie ergibt den Wert 71 und bewirkt die Ausgabe eines »G«.

Operation 1 »1 + 71«

Nachdem nun der Wert 71 des rechten Summanden bekannt ist, kann die Addition ausgeführt werden.

Operatoroperation »1 + 71«
»1 + 71« → »72«

Die Operation »1 + 71« ergibt den Wert 71 und hat keine Wirkung. Diese Operation hat keine Wirkung.

Operation 2 »putchar( 72 )«

Nachdem nun der Wert »72« des Arguments der äußeren putchar-Aufrufs bekannt ist, kann die dazugehörige Operation »putchar( 72 )« ausgeführt werden.

Funktionsoperation »putchar( 72 )«
»putchar( 72 )« → »72« ↓ Ausgabe von »H«

Die Operation »putchar( 72 )« ergibt den Wert 72 und bewirkt die Ausgabe eines »H«.

Zusammenfassung

Der sich zuletzt ergebende Wert »72« wird dann schließlich noch vom Ausdruckrahmen ausgegeben. So kommt es dann insgesamt zur Ausgabe von »GH72«.

main.c

#include <stdio.h>

int main( void )
{ printf( "%d\n", putchar( 1 + putchar( 71 ))); }

Operationen während der Auswertung des Ausdrucks »putchar( 1 + putchar( 71 ))«
»putchar( 71 )« → »71« ↓ Ausgabe von »G«
»1 + 71« → »72«
»putchar( 72 )« → »72« ↓ Ausgabe von »H«
stdout
GH72

Unspezifizierte Sequenzierung bei Argumenten

Ein Teilausdruck ist ein Teil eines Ausdrucks, der selber ein Ausdruck ist. Die Reihenfolge  der Auswertung von Teilausdrücken ist in C  im allgemeinen unspezifiziert.

Except as specified later, side effects and value computations of subexpressions are unsequenced.” — C:2011:6.5p3

Beispielweise ist nicht spezifiziert, daß in dem folgenden Programm der Teilausdruck »putchar( 65 )« vor  dem Teilausdruck »putchar( 66 )« ausgewertet wird.

main.c

#include <math.h>
#include <stdio.h>

int main( void )
{ printf( "%g\n", pow( putchar( 65 ), putchar( 66 ))); }

stdout
AB4.49036e+119
stdout
BA4.49036e+119
Operationssequenz zu »pow( putchar( 65 ), putchar( 66 ))« (erste Möglichkeit)
»putchar( 65 )« → »65« ↓ Ausgabe von »A«
»putchar( 66 )« → »66« ↓ Ausgabe von »B«
»pow( 65, 66 )« → »4.49036e+119«
Operationssequenz zu »pow( putchar( 65 ), putchar( 66 ))« (zweite Möglichkeit)
»putchar( 66 )« → »66« ↓ Ausgabe von »B«
»putchar( 65 )« → »65« ↓ Ausgabe von »A«
»pow( 65, 66 )« → »4.49036e+119«

Unspezifizierte Sequenzierung bei Operanden

Es ist nicht spezifiziert, daß in dem folgenden Programm der Teilausdruck »putchar( 65 )« vor dem Teilausdruck »putchar( 66 )« ausgewertet wird.

#include <math.h>
#include <stdio.h>

int main( void )
{ printf( "%d\n", putchar( 65 )+ putchar( 66 )); }

AB131

Operationssequenz (erste Möglichkeit)
»putchar( 65 )« → »65« ↓ Ausgabe von »A«
»putchar( 66 )« → »66« ↓ Ausgabe von »B«
»65 + 66« → »131«
Operationssequenz (zweite Möglichkeit)
»putchar( 66 )« → »66« ↓ Ausgabe von »B«
»putchar( 65 )« → »65« ↓ Ausgabe von »A«
»65 + 66« → »131«

Übungsfragen

?   Typen und Wertebereich

Diese Übungsfragen gehören zum roten Faden „Würfeln“.

Bei den folgenden beiden Übungsfragen wird die Inklusion des Headers »<stdlib.h>« vorausgesetzt.
Wir haben jetzt gesehen, daß der Wert des Aufrufs »rand()« nicht immer gleich ist. Er kann gemäß der C -Norm irgendein Wert zwischen »0« und »RAND_MAX« sein. Solch eine Unbestimmtheit des genauen Wertes kommt öfter vor. Deswegen ist es hilfreich, zur Übung im Umgang mit ihr die folgenden Fragen  (mit steigendem Schwierigkeitsgrad) zu beantworten:
In welchem Bereich liegt der Wert des Ausdrucks »( ( rand() ))«?
In welchem Bereich liegt der Wert des Ausdrucks »rand()/10«?
In welchem Bereich liegt der Wert des Ausdrucks »rand() - 10«?
In welchem Bereich liegt der Wert des Ausdrucks »rand()/( 1. * RAND_MAX )«?
In welchem Bereich liegt der Wert des Ausdrucks »rand()/( 1. + RAND_MAX )«?
In welchem Bereich liegt der Wert des Ausdrucks »rand()/( 1. + RAND_MAX )* 10«?

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 stefanram724207 stefan_ram:724207 Funktionen variabler Arität in C Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd724207, slrprddef724207, 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/varargs_c