Sonderzeichen in Zeichenfolgenliteralen in C++
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main() { ::std::cout << "Hallo, Welt"s << "\n"s; }
transcript
Hallo, Welt
Zeichenfolgenliterale in C++
Ein Zeichenliteral stellt immer genau ein Zeichen dar. Soll statt dessen eine Zeichenfolge durch einen Ausdruck dargestellt werden, so kann ein Zeichenfolgenliteral verwendet werden. In einfachen Fällen erhält man das Zeichenfolgenliteral aus der Zeichenfolge, indem man diese in Anführungszeichen einschließt.
- Die Zeichenfolge „A“
A
- Das Literal für die Zeichenfolge „A“
"A"s
Dieses Beispiel zur Zeichenfolge „A“ zeigt deutlich, daß man zwischen einer Zeichenfolge und einem Zeichenfolgenliteral unterscheiden muß, da beide offensichtlich nicht übereinstimmen.
Außerdem sieht man, daß man zwischen einem Zeichenliteral und einem Zeichenfolgenliteral immer an Hand der verwendeten Anführungszeichen unterscheiden kann, auch wenn man zwischen dem Zeichen „A“ und der Zeichenfolge „A“ sonst nicht unterscheiden kann.
(Manche C++ -Implementationen melden es nicht als Fehler, wenn ein Zeichenliteral mehrere Zeichen enthält, da dies in manchen Implementation eine spezielle Bedeutung hat. Daher muß der Programmierer selber darauf achten, mit Zeichenliteralen nur ein Zeichen darzustellen.)
Das folgende Programmbeispiel zeigt die Verwendung eines Zeichenfolgenliterals mit einem Zeichen in einem Programm.
hallo.cpp
#include <iostream> // ::std::cout
#include <ostream> // <<
#include <string>using namespace ::std::literals;
int main() { ::std::cout << "A"s << "\n"s; }
::std::cout
A
Das folgende Programmbeispiel zeigt die Verwendung eines Zeichenfolgenliterals mit mehreren Zeichen in einem Programm.
hallo.cpp
#include <iostream> // ::std::cout
#include <ostream> // <<
#include <string>using namespace ::std::literals;
int main() { ::std::cout << "Hallo!"s << "\n"s; }
::std::cout
Hallo
Auch die leere Zeichenfolge kann durch ein Zeichenfolgenliteral dargestellt werden: Das folgende Programm gibt nur eine Leerzeile aus.
hallo.cpp
#include <iostream> // ::std::cout
#include <ostream> // <<
#include <string>using namespace ::std::literals;
int main() { ::std::cout << ""s << "\n"s; }
::std::cout
Die Quellzeichen des Zeichenfolgenliterals sind aber nicht immer mit den Zeichen der bezeichneten Zeichenfolge identisch.
Eine Darstellung eines Zeichens in einem Zeichenfolgenliteral kann nicht immer durch das dem Zeichen gleiche Quelltextzeichen erfolgen. Nicht alle Quelltextzeichen sind in einem Zeichenfolgenliteral erlaubt. So darf in einem Zeichenfolgenliteral etwa keine neue Zeile des Quelltextes begonnen werden.
Soll ein Zeilenendzeichen Teil einer Zeichenfolge sein, so ist es im Zeichenfolgenliteral durch den Quelltext »n« im „Steuerzustand“ (oder „Alternativzustand“) anzugeben. Im Steuerzustand kann jedes Zeichen eine „Steuerbedeutung“ oder „alternative Bedeutung“ haben. So bedeutet das Zeichen »n« in einem Zeichenfolgenliteral normalerweise einfach das Zeichen »n«, im Steuerzustand bedeutet es aber ein Zeilenende.
Dazu nimmt man an, daß man am Anfang eines Zeichenfolgenliterals in einem „Grundzustand“ („Normalzustand“) ist. Im Grundzustand steht das Zeichen »n« im Zeichenfolgenliteral für das Zeichen »n« in der Zeichenfolge. Wenn im Grundzustand jedoch der inverse Schrägstrich »\« auftritt, dann werden die nächsten direkt folgende Zeichen als Steuerzeichenfolge interpretiert. Solche Steuerzeichenfolgen haben eine andere Bedeutung als Zeichenfolgen im Grundzustand. Nach dem Ende einer solchen Steuerzeichenfolge gilt wieder der Grundzustand, ohne daß es eines besonderen Zurückschaltens bedarf. Als Steuerzeichenfolge steht »n« für ein Zeilenende und nicht mehr für den Buchstaben »n«.
- Zeichenfolgenliteral
"a\nb"s
- Text
a
b
In dem obigen Beispiel schaltet der inverse Schrägstrich »\« in den Steuerzustand um. Das »n« wird dann als Steuerzeichenfolge, in diesem Fall also als Zeilenende, interpretiert. Danach gilt für die Interpretation des »b« stillschweigend wieder der Grundzustand.
Diese Regelung gilt auch für Zeichenliterale, was das »'\n'« erklärt, das bisher schon oft verwendet wurde. Es gibt ein einzelnes Zeichen, nämlich ein Zeilenende an, obwohl zwischen den Apostroph-Zeichen im Quelltext zwei Zeichen stehen. Daher entspricht es den Regeln für ein Zeichenliteral, die verlangen, daß nur genau ein Zeichen mit einem Zeichenliteral angegeben wird.
hallo.cpp
#include <iostream> // ::std::cout
#include <ostream> // <<
#include <string>using namespace ::std::literals;
int main() { ::std::cout << "Hallo!"s << "\n"s; }
::std::cout
Hallo
Soll ein Anführungszeichen »"« Teil der notierten Zeichenfolge sein, so ist es im Literal im Grundzustand durch den Quelltext »\"« (ein inverser Schrägstrich und ein Anführungszeichen) zu schreiben. Soll ein inverser Schrägstrich »\« in der Zeichenfolge notiert werden, so ist im Grundzustand der Quelltext »\\« (zwei inverse Schrägstrich) zu schreiben.
- Literal
"a\"b\\n"s
- Zeichenfolge
a"b\n
Man beachte, daß in dem obigen Textliteral die Zeichenfolge "\n" nicht für ein Zeilenende steht, da der inverse Schrägstrich direkt vor dem Quelltext "n" darin nicht im Grundzustand auftaucht, sondern selber bereits als Steuerzeichen. Daher wäre es falsch, sich einfach zu merken, daß »\n« in einem Textliteral immer für ein Zeilenende steht. Um die Bedeutung eines Zeichens zu verstehen, muß man immer auch das Zeichen vor ihm berücksichtigen; das gilt auch für einen inversen Schrägstrich.
Verbindung benachbarter Zeichenfolgenliterale
Mehrere direkt aufeinanderfolgende Zeichenfolgenliterale werden zu einer einzigen Zeichenfolge verbunden. Zwischen ihnen kann Leerraum stehen, also auch eine neue Zeile beginnen.
- Literale
"a"s "b"s
"c"s- Zeichenfolge
abc
Umlaute, das Eszett und andere Sonderzeichen können in C++ zwar unter vielen Umgebungen verarbeitet werden, werden aber hier zunächst vermieden, weil ihre Verwendung etwas kompliziert sein kann.
Das folgende Beispielprogramm zeigt Zeichenfolgenliterale im Zusammenhang eines vollständigen Programmes.
- main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main() { ::std::cout << "// /* Hau"s "s Hof "s "G\nL \"\nS \\ */"s << "\n"s; }
- ::std::cout
// /* Haus Hof G
L "
S \ */
Die Zeichenpaare, welche sonst einen Kommentar einleiten würden, verlieren diese Sonderbedeutung, wenn sie in einem Textliteral vorkommen. Daher sind Kommentare innerhalb von Textliteralen nicht möglich.
Zitat *
- “In translation phase 6 (2.2), adjacent string literals are concatenated and user-defined-string-literals are considered string literals for that purpose.“ … „if a string literal is the result of a concatenation involving at least one user-defined-string-literal, all the participating user-defined-string literals shall have the same ud-suffix and that suffix is applied to the result of the concatenation.” 2.13.8p8
Übungsaufgaben
- / Zeichenfolge ausgeben
- Schreiben Sie ein Programm, das die Zeichenfolge ausgibt, die unter der Überschrift "Text" steht, indem Sie diesen Text mit einem Textliteral notieren. Das Programm soll also eine Zeile mit 18 Zeichen (und nichts anderes) ausgeben.
- Text
"Hallo," sagte er.
- / Programm ausgeben (schwierig)
- Schreiben Sie ein C++ -Programm, das den Quelltext des letzten obenstehenden Programms »main.cpp« (fünf Zeilen) ausgibt.
Rohliterale
Ein einfaches Rohliteral beginnt mit »R"(« und endet mit »)"«.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main()
{ ::std::cout << R"(abc)"s << "\n"s; }Protokoll
abc
Inverse Schrägstriche und Anführungszeichen haben in Rohliteralen keine besondere Bedeutung. (Allerdings beendet die spezielle Zeichenfolge »)"« ein Rohliteral.)
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main()
{ ::std::cout << R"(a\nc"d)"s << "\n"s; }Protokoll
a\nc"d
Rohliteralen können Zeilenenden direkt enthalten.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main()
{ ::std::cout << R"(a
c)"s << "\n"s; }Protokoll
a
c
Falls ein Rohliteral die Zeichenfolge »)"« enthalten soll, so kann es mit bis zu 16 Zeichen markiert werden, die eine andere Zeichenfolge zum Beenden festlegen können. Im folgenden Beispiel wird »%%%« zur Markierung verwendet, so daß dann nicht mehr »)"«, sondern erst »)%%%"« die Zeichenfolge beendet.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main()
{ ::std::cout << R"%%%(R"(a\nc"d)"s)%%%"s << "\n"s; }Protokoll
R"(a\nc"d)"s
Das folgende Beispielprogramm zeigt die Ausgabe einer Multiplikationstabelle mit einem Zeichenfolgenliteral, das nicht roh ist.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main()
{ ::std::cout << /* Multiplikationstabelle */ "\n"s" 0 1 2 3 4 5 6 7 8 9\n"s
" \n"s
" 0 0 0 0 0 0 0 0 0 0 0\n"s
" 1 0 1 2 3 4 5 6 7 8 9\n"s
" 2 0 2 4 6 8 10 12 14 16 18\n"s
" 3 0 3 6 9 12 15 18 21 24 27\n"s
" 4 0 4 8 12 16 20 24 28 32 36\n"s
" 5 0 5 10 15 20 25 30 35 40 45\n"s
" 6 0 6 12 18 24 30 36 42 48 54\n"s
" 7 0 7 14 21 28 35 42 49 56 63\n"s
" 8 0 8 16 24 32 40 48 56 64 72\n"s
" 9 0 9 18 27 36 45 54 63 72 81\n"s; }Protokoll
0 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 0 0
1 0 1 2 3 4 5 6 7 8 9
2 0 2 4 6 8 10 12 14 16 18
3 0 3 6 9 12 15 18 21 24 27
4 0 4 8 12 16 20 24 28 32 36
5 0 5 10 15 20 25 30 35 40 45
6 0 6 12 18 24 30 36 42 48 54
7 0 7 14 21 28 35 42 49 56 63
8 0 8 16 24 32 40 48 56 64 72
9 0 9 18 27 36 45 54 63 72 81
Das folgende Beispielprogramm zeigt die Ausgabe einer Multiplikationstabelle mit einem rohen Zeichenfolgenliteral.
main.cpp
#include <iostream>
#include <ostream>
#include <string>using namespace ::std::literals;
int main()
{ ::std::cout << R"(
0 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 0 0
1 0 1 2 3 4 5 6 7 8 9
2 0 2 4 6 8 10 12 14 16 18
3 0 3 6 9 12 15 18 21 24 27
4 0 4 8 12 16 20 24 28 32 36
5 0 5 10 15 20 25 30 35 40 45
6 0 6 12 18 24 30 36 42 48 54
7 0 7 14 21 28 35 42 49 56 63
8 0 8 16 24 32 40 48 56 64 72
9 0 9 18 27 36 45 54 63 72 81
)"; }Protokoll
0 1 2 3 4 5 6 7 8 9
0 0 0 0 0 0 0 0 0 0 0
1 0 1 2 3 4 5 6 7 8 9
2 0 2 4 6 8 10 12 14 16 18
3 0 3 6 9 12 15 18 21 24 27
4 0 4 8 12 16 20 24 28 32 36
5 0 5 10 15 20 25 30 35 40 45
6 0 6 12 18 24 30 36 42 48 54
7 0 7 14 21 28 35 42 49 56 63
8 0 8 16 24 32 40 48 56 64 72
9 0 9 18 27 36 45 54 63 72 81
Anhang *
Zeichen im Sonderzustand *
In dem Sonderzustand, in den ein einzelner inverser Schrägstrich »\« im Grundzustand umschaltet, haben die folgenden Zeichen Sonderbedeutungen.
- Tabelle
Z. Bedeutung Bed. deutschsprachige Bedeutung
" double quote " Anfuehrungszeichen
' single quote ’ Apostroph
? question mark ? Fragezeichen
\ backslash \ inverser Schraegstricha alert BEL Alarm (Klangsignal, Glocke)
b backspace BS Rueckschritt (u.U. loeschend)
f form feed FF Formularvorschub
n new-line NL Neue Zeile
r carriage return CR Wagenrücklauf
t horizontal tab HT waagerechter Tabulator
v vertical tab VT senkrechter Tabulator
Trigraphen sind veraltete Notationen für bestimmte Sonderzeichen. Beispielsweise stand der Trigraph »??=« für das Nummernzeichen »#«. Um zu verhindern, daß beispielsweise der Trigraph »??=« als »#« interpretiert wird, wenn wirklich diese drei Zeichen gemeint sind, kann darin das zweite Fragezeichen als »\?« geschrieben werden, so daß »?\?=« für die drei Zeichen »??=« und nicht für das Doppelkreuz »#« steht.