Wikibooks
dewikibooks
https://de.wikibooks.org/wiki/Hauptseite
MediaWiki 1.47.0-wmf.19
first-letter
Medium
Spezial
Diskussion
Benutzer
Benutzer Diskussion
Wikibooks
Wikibooks Diskussion
Datei
Datei Diskussion
MediaWiki
MediaWiki Diskussion
Vorlage
Vorlage Diskussion
Hilfe
Hilfe Diskussion
Kategorie
Kategorie Diskussion
Regal
Regal Diskussion
TimedText
TimedText talk
Modul
Modul Diskussion
Veranstaltung
Veranstaltung Diskussion
Diskussion:Wie man eine Sprache lernt
1
41983
1090620
1002671
2026-09-09T12:38:09Z
~2026-48858-58
116863
Neuer Abschnitt /* Mangelnde Neutralität */
1090620
wikitext
text/x-wiki
==Empfehlung des kleinen Prinzen als Lernlektüre==
Hallo, es ist tatsächlich so, dass „Der Kleine Prinz“ von Antoine de Saint-Exupéry“ immer wieder in Schulen als Lerntext verwendet wird. Auch ich wurde zusammen mit einigen anderen Mitschülern mit diesem Text gequält. Ich möchte dessen allgemeingültige Tauglichkeit für Zwecke des Fremdsprachenlernens schwer anzweifeln. Denn es gibt viele Schüler, die mit diesem Text schon auf Deutsch nicht viel anfangen können, ihn als Kitsch und als stinklangweilig empfinden. Einige meiner Mitschüler haben es damals schon nicht verstanden - und genau so geht es mir persönlich heute noch - warum beispielsweise der kleine Prinz in kleinen Welt lebt. Das sind genau die Schüler, die weniger schöngeistig und oft mehr naturwissenschaftlich veranlagt sind. Diese Schüler werden bei der Auswahl der Texte zum Erlernen der Fremdsprache in aller Regel in den Schulen benachteiligt. Schuld daran ist die in aller Regel schöngeistige Ausrichtung der Fremdsprachenlehrer als auch die der zuständigen Personen in den Verlagen, die kein Problem mit der Schöngeistigkeit dieses Textes haben und sich auch nicht im Entferntesten vorstellen können, dass es Leute gibt, bei denen das anders ist. Sie wundern sich dann womöglich, warum manche Schüler die Fremdsprache schlecht lernen, können es aber aufgrund ihrer schöngeistig beschränkten Sichtweise nicht nachvollziehen. Fast niemals wird man es daher erleben, dass ein eher naturwissenschaftlich ausgerichteter Text als Grundlage für das Sprachenlernen genutzt wird, weil er der Masse der Fremdsprachenlehrer nicht liegt. Solch ein Text würde dann eher die schöngeistig besaiteten Schüler benachteiligen.
Wer schöngeistig nicht soviel drauf hat, bekommt in Deutsch eine schlechte Note. Das mag so richtig und sinnvoll sein. Die gleiche Person in der Fremdsprachennote nochmals wegen dieser fehlenden Eigenschaft zu "bestrafen", obwohl sie in der Lage ist, sich perfekt mit einem Muttersprachler über Alltagsprobleme oder naturwissenschaftliche Fachthemen unterhalten zu können, halte ich aber für äußerst fragwürdig.
Nun wird auch hier im Wikibook der kleine Prinz als bevorzugter Lerntext empfohlen. Dem Autor dieses Satzes unterstelle ich hierbei einmal beste Absichten. Er hat das, was man in der Schule verbreitet als sinnvoll erachtet, hier weitergegeben. Nun sind wir hier aber unter Erwachsenen und diejenigen, die in der Schule eine schlechte Fremdsprachennote hatten, sind nun nicht mehr dem Diktat des Lehrers unterlegen und können aufgrund inzwischen erworbener den Hintergründen ihrer schlechten Noten auf die Spur kommen. So würde ich also den kleinen Prinzen individuell nur denjenigen empfehlen, die eine schöngeistige Ader haben. Für komplette Klassen oder als allgemeingültig sinnvoller Text kann er aus oben genannten Gründen eher nicht dienen. Hier wären eher Texte sinnvoll, die niemand benachteiligen und folglich schon in deutschen Fassung von jedem verstehbar sind. Ich sehe da als einzige Alternative Texte, die schon in der deutschen Version heutige Gebrauchssprache verwenden und dort von jedem verstehbar sind. Zumal bei einer Kommkunikation in der Fremdsprache in aller Regel genau diese angewendet wird und nicht die des kleinen Prinzen. Ansatzpunkte für eine Veränderung sehe ich bei den ersten Versuchen in den Verlagen, Krimis in mehrsprachigen Versionen herauszubringen, was aber zumindest im Umfeld meines Bekanntenkreises in den Schulen nicht genutzt wird. -- [[Benutzer:84.132.107.129|84.132.107.129]] 18:53, 7. Apr. 2007 (CEST)
:Schöngeistig hin oder her: als Einstiegslektüre taugt „Der Kleine Prinz“ nun wirklich nicht. Da ist Tolkiens „Der kleine Hobbit“ wirklich besser. -- [[Benutzer:McKaot|McKaot]] 17:30, 26. Jan. 2009 (CET)
== richtig und falsch ==
Dieser Artikel gibt eine Anleitung zum Sprachenlernen und ist damit nur eine Ausarbeitung unter tausenden. Über die Jahre sind zahlreiche Sprachenlernmethoden entwickelt worden. Jede behauptet von sich, die einzig wahre zu sein. Ich vertrete die These, dass ein Konsens niemals möglich sein wird. Wir müssen uns damit abfinden, dass es stets mehrere bekannte und unabzählbar viele unbekanntere Theorien geben wird; genauso, wie wir es akzeptieren müssen, dass es keine Weltplansprache gibt, weil Plansprachen gegenüber natürlich gewachsenen den Nachteil haben, dass Diskussionen denkbar sind. Aber ich schweife ab.
Jedenfalls ist es nicht die Aufgabe von Wikibooks, unantastbare „Wahrheiten“ zu etablieren. Ich lerne momentan Kastilisch nach der Methode von [[w:Vera F. Birkenbihl|Vera F. Birkenbihl.]] (sie beschreibt diese auf ihrem [http://birkenbihl-insider.de/ Internetauftritt] unter Texte → Punkt 11, Sprachenlernen leicht gemacht) Ich möchte hier nicht als Missionar auftreten, möchte aber anmerken, dass ich von ihren psychologischen Ansätzen überzeugt bin. Wenn man einer Bewertung dieses Artikels im jetzigen Zustand VFBs Aussagen zugrunde legt, kommt man zu dem Schluss, dass die Hälfte seines Inhaltes ausgemachter Humbug ist.
Wohlgemerkt: Es kommt auf die subjektive Haltung zum Thema Sprachenlernen an. Deshalb will ich auch nicht den Inhalt dieses Artikels in Frage stellen und will ihn auch nicht verbessern, weil „verbessern“ hier nicht das passende Wort ist. Ich bitte nur um Ideen, wie wir die Wikibooks-Nutzer in das Sprachenlernen einweihen können, ohne einen Perfektionsanspruch zu erheben, wie es dieser Artikel gegenwärtig tut.
Ich plane, einige Sprachkurse (angefangen mit Deutsch für verschiedene Quellsprachen) in Anlehnung an die Methoden von VFB und dem [http://assimil.de/ ASSiMiL-Verlag] für Wikibooks zu initiieren. Nun sind für einige Zielsprachen schon derartige – meiner Meinung nach aussichtslose, da an nicht funktionierenden Schulunterricht erinnernde – Projekte vorhanden, die ich mit diesem Vorhaben keinesfalls delegitimieren möchte, die aber nicht mit meiner Vorstellung von einem erfolgversprechenden Sprachkurs vereinbar sind.
Könnten wir vielleicht sämtlichen Theorien in gewisser Weise eine Chance geben? Ich weiß nicht, wie das geschehen kann; deshalb schreibe ich das hier. Aber es müsste dem Nutzer freigestellt sein, ''wie'' er sein Lernziel erreichen möchte. [[Benutzer:Nowotoj|новое тождество]] 20:09, 10. Apr. 2007 (CEST)
:Ich denke, ob manche der Hinweise ausgemachter Humbug sind, kann allgemeinverbindlich wohl kaum gesagt werden. Jeder ist anders gestrickt. Manche Tipps mögen für den einen passen, während sie für andere nutzlos sind. Jeder der angegebenen Tipps dürfte irgendjemand schon einmal geholfen hat. Daher hat er seine Berechtigung und wurde er hier eingestellt. Jeder Leser kann die diversen Tipps ausprobieren und muss dann aus dem Gesagten das für ihn Sinnvolle heraussuchen. Insofern ist hier eine möglichst große Vielfalt sinnvoll und gewünscht. -- [[Benutzer:84.132.73.224|84.132.73.224]] 19:10, 23. Mai 2007 (CEST)
Wie wäre es denn, wenn man innerhalb der Sprachkurse ein Zwischenkapitel etabliert und die Sprachkurse nach dem Muster "Sprache/Lerntechnik/Inhalt" aufgebaut werden? So könnten mehrere Lernmethoden nebeneinander existieren und jeder Lerner (m/f) die für ihn passende Methode wählen - lieber Oldschool oder lieber Frau Birkenbiehl ... -- [[Spezial:Contributions/79.226.180.103|79.226.180.103]] 09:55, 23. Juli 2009 <small>(Signatur nachgetragen von: [[Benutzer:Juetho|Jürgen]] 18:36, 27. Apr. 2013 (CEST) -- bitte künftig mit 4 Tilden <nowiki>~~~~</nowiki> selbst erledigen)</small>
==Sprachen lernen nach dem 7. Lebensjahr==
"Allgemein gesagt, wird jeder, der eine Sprache nach seinem siebenten Lebensjahr zu lernen beginnt, einen leichten Akzent behalten."
Mein ehemaliger Professor der Phonetik, Prof. Hess, war allerdings der Meinung, dass das Erlernen von Fremdsprachen wesentlich vom genauen Hören abhängt, und dass jemand, der genau zuhört, durchaus in der Lage ist, eine Sprache akzentfrei zu lernen. Meines Wissens stand/steht er mit dieser Auffassung nicht alleine da. -- [[Spezial:Contributions/Darkmind0374|Darkmind0374]] 21:54, 28. Dez. 2009 <small>(Signatur nachgetragen von: [[Benutzer:Juetho|Jürgen]] 18:36, 27. Apr. 2013 (CEST) -- bitte künftig mit 4 Tilden <nowiki>~~~~</nowiki> selbst erledigen)</small>
== Erwachsene und Grammatik ==
wer hat Ihnen gesagt, die Hanafi-Methode sei gut für Grammatik???? Kein Erwachsener lernt Grammatik "automatisch" aus....... wer das hier gepostet hat, hat keine Ahnung von Neurologie und Psychologie des Lernens.
++[[Spezial:Beiträge/89.43.195.27|89.43.195.27]] 18:06, 27. Apr. 2013 (CEST)
== Besser gliedern ==
Die heutigen Ergänzungen sind eigentlich zu loben. An den vielen Korrekturen hin und her kann man aber erkennen, dass eine solche Überarbeitung schwierig ist. Mir kommt es vor, als ob verschiedene Abschnitte zu unterschiedlichen Lernmethoden gehören, aber durcheinander folgen. Vielleicht wäre folgendes Vorgehen zu empfehlen:
* [[Benutzer Diskussion:Sprachenjunkie|Sprachenjunkie]] speichert alle seine Änderungen lokal auf seiner Festplatte, damit sie nicht verlorengehen.
* Ein Admin (also ich) macht alle heutigen Änderungen rückgängig.
* Als nächstes wird die Gliederung ausgebaut: z.B. Methoden, Lernschritte, Maßnahmen
* Danach ist es wahrscheinlich sinnvoll, einzelne Abschnitte [[Hilfe:Buch in Kapitel untergliedern|in Kapitel zu untergliedern]] (also mit getrennten Seiten).
* Diese Gliederung kann dann mit den heutigen Inhalten neu gefüllt werden.
Bitte nicht ärgern und wundern: Das ist ''mein'' Eindruck von den heutigen Änderungen. Mein Ziel ist, dass diese Anmerkungen zu einer Verbesserung des Buches führen. -- Gruß [[Benutzer:Juetho|Jürgen]] 17:54, 14. Mai 2013 (CEST)
Huhu,
Wenn man in die History des Buches schaut, ist dies eine Übersetzung aus dem englischen Wikibook-Projekt, wo dieses "Buch" auch gegliedert ist. Nun wollte ich einen Vorschlag machen, wie wäre es den Artikel in [[Allgemeine Tipps zum Aneignen einer Fremdsprache]] oder ähnlichem umzubenennen, weil der Titel jetzt ist irreführend, weil Hirnwissenschafter und andere würde sicher das Lernen einer/von Sprache anders darstellen, Grüße -[[Benutzer:Zase Wieder|Zase Wieder]] 14:28, 27. Sep. 2022 (CEST)
== the 4 hour man - Timothy Ferriss ==
Joa Ferriss hats auch hinein geschafft also was soll ich schreiben,
Timothy Ferriss hat eine völlig neue Technik entwickelt wie man Sprachen innerhalb kürzester Zeit lernen kann. Und zwar mega schnell verschiedenste Sprachen untersucht es selbst in seinem neuen buch keine ahnung gibs bei ytorrent zu kaufen also wenn ihr lust habt schreibt es hier hinein ich glaube es reicht dafür schon die kostenlose vorabversion sodass keine kosten entstehen und schwupps die wupps haben die leute die sprache gelernt mit ohne ende eselsbrücken. Also macht euch ran für sowas skripts ins internet zu stellen sodass jeder die fremden sprachen in null komma nix lernen könnnen ich will einsatz sehen!
DAnke für das lesen dieser Nachricht bitte spenden Sie an Wikipedia auf Lebenszeit!
MIt freundlichen Grüßen
Roflmaster
== Mangelnde Neutralität ==
In Verbindung mit dem Titel des Books halte ich die einseitige Propagierung der Birkenbihl-Methode für unausgewogen. Gerade neuere (vor allem immersive) Konzepte und Methoden sind sowohl theoretisch sauberer fundiert und auch insbesondere international gängiger. Keine Berücksichtigung findet auch das Lernen von Fremdsprachen mithilfe von Brückensprachen.
Nicht zuletzt halte (nicht nur) ich die Person Vera Birkenbihl für problematisch, besonders wegen unfundierter Verbreitung von (vor allem in Bezug auf geschlechterspezifisches Lernen) pseudowissenschaftlichen und längst widerlegten Inhalten. [[Spezial:Beiträge/~2026-48858-58|~2026-48858-58]] ([[Benutzer Diskussion:~2026-48858-58|Diskussion]]) 14:38, 9. Sep. 2026 (CEST)
t0rz6j9c3yqt1ucc86tnw9k1erjolso
Traktorenlexikon: Başak
0
70472
1090645
1077306
2026-09-10T09:48:28Z
~2026-46367-92
116784
1090645
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation}}
Başak bedeutet im türkischen einmal Ehre und ist zum 2. ein Vorname, dem die Eigenschaften fest oder solide zugeschrieben werden.
==Geschichte==
'''Başak Traktör''' ist ein türkischer Traktorenhersteller. Gegründet 1914 stellte die Firma von Anfang der 1960er Jahre bis 1996 Traktoren unter der Lizenz von [[Traktorenlexikon: Ford|Ford]] und [[Traktorenlexikon: Steyr|Steyr]] her.
2023 übernahm Başak etwa 93% von Versatile. 2025 übernahm dann die türkische ASKO Holding, der Mutterkonzern von Başak, auch die restlichen Anteile von [[Traktorenlexikon: Versatile|Versatile]].
==Typen==
[[Datei:Basak 2060 BK.JPG|miniatur|Başak 2060 BK]]
Es wurden Schlepper mit folgenden Typenbezeichnungen vertrieben:
===2043-Serie===
{{:Traktorenlexikon:_Create|2043 SH SK}}
===2050-Serie===
{{:Traktorenlexikon:_Create|2050 ASH KK Turbo}}
{{:Traktorenlexikon:_Create|2050 ASH SK Turbo}}
{{:Traktorenlexikon:_Create|2050 SH KK}}
{{:Traktorenlexikon:_Create|2050 SH KK Turbo}}
{{:Traktorenlexikon:_Create|2050 SH SK}}
===2053-Serie===
{{:Traktorenlexikon:_Create|2053 SH SK}}
{{:Traktorenlexikon:_Create|2053 SH Cabin}}
===2073-Serie===
{{:Traktorenlexikon:_Create|2073 ASH KAGKK Turbo}}
{{:Traktorenlexikon:_Create|2073 ASH SK TK}}
{{:Traktorenlexikon:_Create|2073 ASH SK Turbo}}
{{:Traktorenlexikon:_Create|2073 SH KAGKK}}
{{:Traktorenlexikon:_Create|2073 SH KAGSK}}
{{:Traktorenlexikon:_Create|2073 SH SK}}
{{:Traktorenlexikon:_Create|2073 SH SK Cabin}}
{{:Traktorenlexikon:_Create|2073 SH SK Turbo}}
== Weblinks ==
{{commonscat|Basak Traktor}}
* [http://www.basaktraktor.com.tr/ Webseite der Firma]
{{:Traktorenlexikon: Navigation}}
57z63w92ypx1rg65xmnvncz17b5rkia
Traktorenlexikon: Deutz-Fahr DX 160
0
87338
1090617
1089850
2026-09-09T12:14:06Z
JaWa1998
115962
1090617
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Deutz-Fahr |HERSTELLER= Deutz-Fahr}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = Deutz-Fahr
| MODELLREIHE = DX-Reihe
| MODELL = DX 160
| BILD = DX 160.jpg
| BILDBESCHREIBUNG = Deutz-Fahr DX 160
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1978
| PRODUKTIONSENDE = 1984
| STÜCKZAHL = 62
| EIGENGEWICHT = 5.400 (A: 5.850)
| LÄNGE = 4.710 (A: 4.770)
| BREITE = 2.370
| HÖHE = 2.730
| RADSTAND = 2.631 (A: 2.826)
| BODENFREIHEIT = 605 (A: 490)
| SPURWEITE VORNE = 1.596-2.196 (A: 1.860/2.000)
| SPURWEITE HINTEN = 1.800-2.200
| WENDERADIUS MIT LENKBREMSE = 4.470
| WENDERADIUS OHNE LENKBREMSE = 4.850 (A: 6.770)
| BEREIFUNG VORNE = 11.00-16 ASF (A: 18.4-26 AS)
| BEREIFUNG HINTEN = 20.8-38 AS
| LEISTUNG KW = 110,4
| LEISTUNG PS = 150
| NENNDREHZAHL = 2.200
| ZYLINDER = 6
| HUBRAUM = 6.128
| DREHMOMENTANSTIEG = 15
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Luftkühlung
| ANTRIEBSTYP = Hinterrad-oder Allradantrieb
| GETRIEBE = 24V/8R
| HÖCHSTGESCHWINDIGKEIT = 25 oder 30
| KATEGORIESORTIERUNG = Deutz-Fahr DX 160
}}
Der '''Deutz DX 160''' gehört zur '''1978''' eingeführten, neu entwickleten '''DX-Serie''' von Deutz. Er war direkt ab Marktstart erhältlich und stellte dabei das stärkste Modell der DX-Serie dar. Er hatte keinen direkten Vorgänger und wurde vollständig neu entwickelt. Er spielt zwar in der gleichen Leistungsklasse wie der [[Traktorenlexikon: Deutz D 16006|D 16006]] der Vorgängerserie, dieser basierte aber auf einem umgedrehten Radlader und hatte bis auf die Leistung keine Gemeinsamkeiten. Er bekam den neuen Turbo-aufgeladenen '''BF6L913'''-Motor mit 150PS. Da Deutz für den Leistungsbereich oberhalb von 120PS noch kein eigenes Getriebe entwickelt hatte, ging KHD eine Zusammenarbeit mit dem österreichischen Hersteller '''STEYR''' ein. Der DX 140 nutzte das Steyr-Triebwerk '''TW1200''' mit 2-facher, bei Deutz '''"Powermatic"''' genannten Lastschaltung, die über zwei Druckknöpfe im Armaturenbrett bedient wurde.
Die Anordnung des Steyr-Triebwerks entsprach dem des TW90-Triebwerks, allerdings mit nur vier Gängen. Um das Lastschaltgetriebe in einer 25 km/h sowie einer 30 km/h-Variante anbieten zu können, musste die Gesamtübersetzung angepasst werden. Leider entwickelte sich die Ersatzteilversorgung mit den Jahren problematisch.
Beim DX 160 wurde die '''MasterCab'''-Kabine serienmäßig angeboten. Zur Allrad-Variante bot Deutz auch weiterhin eine Hinterradantrieb-Variante an, die aber ausschließlich für den Export bestimmt war.
Nach 6 Jahren Bauzeit wurde der '''DX 160''' 1984 durch seinen 10PS stärkeren Nachfolger [[Traktorenlexikon: Deutz-Fahr DX 7.10|DX 7.10]] ersetzt.
==Motor==
* KHD, Typ: BF6L 913, stehender-luftgekühlter Viertakt-Sechszylinder-Reihen-Turbomotor mit Direkteinspritzverfahren, Druckumlaufschmierung mittels Zahnradpumpe, Kolbenkühlung, Bosch-Kraftstoffpumpe, zahnradgetriebener Nockenwelle, Dreiring-Leichtmetall-Kolben, Bosch-Reihen-Einspritzpumpe, hängenden Ventilen, Trockenluftfilter mit Zyklon-Vorabscheider, Bosch-Fliehkraftregler, siebenfach-gelagerter Kurbelwelle, integrierter Motorölkühler, Einzel-Aluminium-Zylinderköpfe, Bosch-Mehrloch-Düsen, KKK-Abgasturbolader und Axial-Regelgebläse.
* Bohrung = 102 mm, Hub = 125 mm
* Verdichtung = 15,5 : 1
* Drehmoment bei Höchstleistung = 480 Nm
* Max. Drehmoment = 533 Nm bei 1.602 U/min.
* Leerlaufdrehzahl = 650 bis 750 U/min.
* Geregelter Drehzahlbereich = 700 bis 2.340 U/min.
* Max. Einspritzdruck = 175 + 8 bar
* Einspritzmenge = 79 mm³/Hub und Nenndrehzahl
* Max. Ladedruck = 440 mbar
* Bosch-Kraftstoffpumpe, Typ: FB/KS 22 AD 23/2
* Bosch-Drehzahlregler, Typ: EP/RSV 325-1150 A 8 B 2020 DL
* Bosch-Einspritzpumpe, Typ: PES 6 A 85 D 410 RS 2537
* Bosch-Mehrloch-Düse, Typ: DLLA 149 S 490
* Kühnle, Kopp und Kausch-Turbolader, Typ: 3 LEP 229 A/13.2
==Kupplung==
* trockene Einfachkupplung
* Pedal betätigt
* 350 mm Durchmesser
* Typ: LuK 350 DGFP
==Getriebe==
'''Merkmale'''
* Im Ölbad laufendes Steyr-Getriebe, Typ: '''STEYR TW 1200''' mit Seitenschaltung
* Vollynchronisiertes Wechselgetriebe mit vier Gängen
* Auf Wunsch Vorschaltgetriebe als zweistufige Lastschaltung zur Verdoppelung der Ganganzahl ('''DEUTZ-POWERMATIC''')
* Gruppen-Getriebe mit drei Vorwärts- und einer Rückwärtsgruppe, in die Bereiche L-M-H und R unterteilt
* Gruppen L und H mit Klauenschaltung
* Gruppen M und R mit Synchronschaltung
'''Eigenschaften'''
* Gangzahl vorwärts/rückwärts = 12/4
* Auf Wunsch mit '''DEUTZ-POWERMATIC''' = 24/8
* Auf Wunsch mit '''DEUTZ-POWERMATIC''' und Kriechgängen = 36/12
'''Gesamtübersetzung der Lastschaltstufe in Stellung "HI"'''
'''Ab 1982'''
* Im Ölbad laufendes Steyr-Powermatic-Getriebe, Typ: TW-1300 mit Seitenschaltung
* Synchronisiertes Wechsel- und Gruppengetriebe, incl. zweistufiger Lastschaltung
* 24 Vorwärts- und 8 Rückwärtsgänge bzw. 36 Vorwärts- und 12 Rückwärtsgänge
Gesamtübersetzung-Triebwerk TW-1200
* Lastschaltstufe-LO
"Gruppe-L"
* 1.Gang = 344,02:1
* 2.Gang = 245,00:1
* 3.Gang = 177,82:1
* 4.Gang = 127,67:1
"Gruppe-M"
* 1.Gang = 206,69:1
* 2.Gang = 147,19:1
* 3.Gang = 106,83:1
* 4.Gang = 76,70:1
"Gruppe-H"
* 1.Gang = 94,67:1
* 2.Gang = 67,42:1
* 3.Gang = 48,93:1
* 4.Gang = 35,13:1
"Gruppe-R"
* 1.Gang = 199,02:1
* 2.Gang = 141,74:1
* 3.Gang = 102,87:1
* 4.Gang = 73,86:1
* Lastschaltstufe-HI
"Gruppe-L"
* 1.Gang = 274,18:1
* 2.Gang = 195,26:1
* 3.Gang = 141,72:1
* 4.Gang = 101,7:1
"Gruppe-M"
* 1.Gang = 164,73:1
* 2.Gang = 117,31:1
* 3.Gang = 85,15:1
* 4.Gang = 61,30:1
"Gruppe-H"
* 1.Gang = 75,45:1
* 2.Gang = 53,73:1
* 3.Gang = 39,00:1
* 4.Gang = 28,00:1
"Gruppe-R"
* 1.Gang = 158,62:1
* 2.Gang = 112,96:1
* 3.Gang = 81,99:1
* 4.Gang = 58,86:1
* Optionale Kriechgruppe:
"Gruppe-L"
* 1.Gang = 2315,33:1
* 2.Gang = 1648,89:1
* 3.Gang = 1196,77:1
* 4.Gang = 859,22:1
"Gruppe-M"
* 1.Gang = 1391,03:1
* 2.Gang = 990,64:1
* 3.Gang = 719,01:1
* 4.Gang = 516,21:1
"Gruppe-H"
* 1.Gang = 637,14:1
* 2.Gang = 453,75:1
* 3.Gang = 329,33:1
* 4.Gang = 236,44:1
"Gruppe-R"
* 1.Gang = 1339,45:1
* 2.Gang = 953,90:1
* 3.Gang = 692,35:1
* 4.Gang = 497,07:1
==Geschwindigkeiten vor- und rückwärts==
Geschwindigkeiten-Triebwerk TW-1200 in der 25 km/h.-Ausführung mit Bereifung 20.8-38 AS
* Lastschaltstufe-LO
"Gruppe-L"
* 1.Gang = 2,06 km/h
* 2.Gang = 2,89 km/h
* 3.Gang = 3,99 km/h
* 4.Gang = 5,55 km/h
"Gruppe-M"
* 1.Gang = 3,43 km/h
* 2.Gang = 4,82 km/h
* 3.Gang = 6,64 km/h
* 4.Gang = 9,25 km/h
"Gruppe-H"
* 1.Gang = 7,49 km/h
* 2.Gang = 10,52 km/h
* 3.Gang = 14,49 km/h
* 4.Gang = 20,19 km/h
"Gruppe-R"
* 1.Gang = 3,56 km/h
* 2.Gang = 5,00 km/h
* 3.Gang = 6,89 km/h
* 4.Gang = 9,60 km/h
* Lastschaltstufe-HI
"Gruppe-L"
* 1.Gang = 2,59 km/h
* 2.Gang = 3,63 km/h
* 3.Gang = 5,00 km/h
* 4.Gang = 6,97 km/h
"Gruppe-M"
* 1.Gang = 4,30 km/h
* 2.Gang = 6,04 km/h
* 3.Gang = 8,33 km/h
* 4.Gang = 11,57 km/h
"Gruppe-H"
* 1.Gang = 9,40 km/h
* 2.Gang = 13,20 km/h
* 3.Gang = 18,18 km/h
* 4.Gang = 25,33 km/h
"Gruppe-R"
* 1.Gang = 4,47 km/h
* 2.Gang = 6,28 km/h
* 3.Gang = 8,65 km/h
* 4.Gang = 12,05 km/h
* Optionale Kriechgruppe:
"Gruppe-L"
* 1.Gang = 0,31 km/h
* 2.Gang = 0,43 km/h
* 3.Gang = 0,59 km/h
* 4.Gang = 0,83 km/h
"Gruppe-M"
* 1.Gang = 0,51 km/h
* 2.Gang = 0,72 km/h
* 3.Gang = 0,99 km/h
* 4.Gang = 1,37 km/h
"Gruppe-H"
* 1.Gang = 1,11 km/h
* 2.Gang = 1,56 km/h
* 3.Gang = 2,15 km/h
* 4.Gang = 3,00 km/h
"Gruppe-R"
* 1.Gang = 0,53 km/h
* 2.Gang = 0,74 km/h
* 3.Gang = 1,02 km/h
* 4.Gang = 1,43 km/h
'''Geschwindigkeiten-Triebwerk TW-1300 in der 30 km/h.-Ausführung mit Bereifung 20.8-38 AS'''
'''Lastschaltstufe-LO'''
"Gruppe-L"
* 1.Gang = 2,4 km/h
* 2.Gang = 3,4 km/h
* 3.Gang = 4,7 km/h
* 4.Gang = 6,6 km/h
"Gruppe-M"
* 1.Gang = 4,1 km/h
* 2.Gang = 5,7 km/h
* 3.Gang = 7,8 km/h
* 4.Gang = 10,9 km/h
"Gruppe-H"
* 1.Gang = 8,8 km/h
* 2.Gang = 12,4 km/h
* 3.Gang = 17,1 km/h
* 4.Gang = 23,8 km/h
"Gruppe-R"
* 1.Gang = 4,2 km/h
* 2.Gang = 5,9 km/h
* 3.Gang = 8,1 km/h
* 4.Gang = 11,3 km/h
'''Lastschaltstufe-HI'''
"Gruppe-L"
* 1.Gang = 3,1 km/h
* 2.Gang = 4,3 km/h
* 3.Gang = 5,9 km/h
* 4.Gang = 8,2 km/h
"Gruppe-M"
* 1.Gang = 5,1 km/h
* 2.Gang = 7,1 km/h
* 3.Gang = 9,8 km/h
* 4.Gang = 13,7 km/h
"Gruppe-H"
* 1.Gang = 11,1 km/h
* 2.Gang = 15,6 km/h
* 3.Gang = 21,4 km/h
* 4.Gang = 30,0 km/h
"Gruppe-R"
* 1.Gang = 5,3 km/h
* 2.Gang = 7,4 km/h
* 3.Gang = 10,2 km/h
* 4.Gang = 14,2 km/h
'''Optionale Kriechgruppe'''
"Gruppe-L"
* 1.Gang = 0,36 km/h
* 2.Gang = 0,51 km/h
* 3.Gang = 0,70 km/h
* 4.Gang = 0,97 km/h
"Gruppe-M"
* 1.Gang = 0,60 km/h
* 2.Gang = 0,84 km/h
* 3.Gang = 1,16 km/h
* 4.Gang = 1,62 km/h
"Gruppe-H"
* 1.Gang = 1,31 km/h
* 2.Gang = 1,84 km/h
* 3.Gang = 2,54 km/h
* 4.Gang = 3,54 km/h
"Gruppe-R"
* 1.Gang = 0,62 km/h
* 2.Gang = 0,88 km/h
* 3.Gang = 1,21 km/h
* 4.Gang = 1,68 km/h
==Zapfwelle==
* Unabhängige Motorzapfwelle
* Elektrohydraulisch betätigt und lastschaltbar
* 1.000/min b. Motordrehzahl 1.920/min
* Übertragbare Leistung = 94,5 kW ~ 129 PS
* Stummel = 1 3/8" - 21-teilig (Form-B)
"Ab 1982"
* Elektrohydraulisch-betätigte, unabhängige und lastschaltbare Motorzapfwelle mit zwei Geschwindigkeiten
* Stummel drehbar, 1 3/8"-21 teilig (Form-2) oder 1 3/8"-6 Keile (Form-1)
* Drehzahlen = 540 und 1.000 U/min.
==Bremsen==
'''Betriebsbremse'''
* hydraulisch betätigte, nasse GIRLING-Vollscheibenbremse
* Auf die Differentialseitenwellen wirkend, als Einzelrad-Bremse zu verwenden
* Lamellen-Bremse mit sechs Belagscheiben, je eine links und rechts mit 222 mm Durchmesser
'''Feststellbremse'''
* Unabhängige, mechanisch betätigte Feststellbremse
* Auf die Betriebsbremse wirkend
* Auf Wunsch auf eigene Belagscheiben wirkend
'''Verzögerungswerte'''
* Max. Verzögerung = 3,9 m/s²
* Pedalkraft = 25 daN
* Bremsweg bei 25 km/h = 7,8 m
'''Optional'''
* Zweikreis-Druckluftbremsanlage
* Kombinierte Ein-und Zweikreis-Druckluftbremsanlage
==Achsen==
'''Vorderachsen'''
''Bei Hinterradantrieb (2WD)''
* Pendelnd-gelagerte Teleskop-Vorderachse, Typ: '''KHD Tele-03'''
* Spurweite sechsfach-verstellbar in Stufen von 100 mm = 1.596 bis 2.196 mm
''Bei Allradantrieb (4WD)''
* pendelnd-gelagerte, elektrohydraulisch-betätigte und lastschaltbare ZF-Lenktriebachse, Typ: '''ZF APL-3052''' mit seitlicher Gelenkwelle
* Übersetzungsverhältnis = '''1,346'''
* Spurweiten durch Radumschlag = 1.800 oder 2.000 mm
'''Hinterachse'''
* Hinterachse mit Kegelradgetriebe, Tellerrad und Planetengetriebe
* Vierfache Spurverstellung durch Radumschlag und Radscheiben, in Stufen von 100 mm = 1.600 bis 2.200 mm
* Pedal betätigte, selbstausrückende und lastschaltbare Differentialsperre
'''Achslasten'''
''bei Allradantrieb''
* Vorderachslast = 2.320 kg (2WD = 1.920 kg)
* Zul. Vorderachslast = 3.600 kg (2WD = 2.800 kg)
* Hinterachslast = 3.530 kg (2WD = 3.480 kg)
* Zul. Hinterachslast = 6.180 kg (2WD = 6.500 kg)
==Lenkung==
'''Lenkanlage'''
* Hydrostatische ZF-Lenkung, Typ: '''ZF Servostat 8452''' mit eigenem Ölkreislauf
* Lenkzylinder mit 50 mm Kolbendurchmesser und 250 mm Kolbenhub
'''Hydraulische Versorgung'''
* Bosch-Pumpe, Typ: HY/ZFS 11/19 L
* Förderleistung je Pumpenumdrehung = 19 cm³
* Fördermenge = 45 l/min.
==Hydrauliksystem und Kraftheber==
'''Kraftheber'''
* DEUTZ-TRANSFERMATIC-SYSTEM K55.2 mit 2 Zusatzhubzylindern mit Unterlenkerregelung
* Pumpenantrieb direkt vom Getriebe
* Dreipunktkupplung = Kat. II (Wunsch Kat. III)
* Zusatzsteuergeräte = max. 3
'''Funktionen'''
* Heben, Senken, Neutral- und Schwimmstellung, Lage- und Zugkraftregelung
* Hubhöhenbegrenzung, Seitenstabilisierung und Transportsicherung
'''Hydraulische Versorgung'''
* Bosch-Zahnradpumpe, Typ: HY/ZFS 11/22,5 l
* Förderleistung je Pumpenumdrehung = 22,5 cm³
* Fördermenge = 58,5 l/min
* Arbeitsdruck = 175 bar
'''Leistung'''
* Leistung der Hydraulik = 16,2 kW
* Max. Hubkraft an den Koppelpunkten = 63.800N (6.500kp ~ 6.500kg)
==Steuergeräte==
* 1 DW Steuergerät
* Optional bis zu zwei weitere EW oder DW Zusatz-Steuergeräte
==Elektrische Ausrüstung==
* 12 Volt-Einrichtung nach StVZO
* Batterie, 12 V-143 Ah
* Bosch-Anlasser, ID 12 V-3.7 kW
* Bosch-Lichtmaschine mit integriertem Regler, G1 14 V-65 A 22
==Maße und Abmessungen==
'''Allrad'''
* Bei Bereifung vorn/hinten = 14.9-28/20.8-38
* Radstand = 2.826 mm
* Länge = 4.716 mm
* Breite = 2.370 mm
* Höhe über Lenkrad = 2.125 mm
* Höhe über Auspuff = 2.920 mm
* Höhe über offene Auspuffklappe = 3.050 mm
* Bodenfreiheit unter Allradachse = 480 mm
* Spurweiten vorn = 1.800 u. 2.000 mm
* Spurweiten hinten = (1.600) 1.700 ... 2.200 mm
* Wenderadius o. Lenkbremse = 6.340 mm
* Leergewicht = 5.850 kg
* Zul. Gesamtgewicht = 8.500 kg
'''Geänderte Werte durch Hinterradantrieb-Ausführung'''
* Länge = 4.710 mm
* Höhe über Auspuff = 2.790 mm
* Radstand = 2.631 mm
* Bodenfreiheit unter der Teleskop-Achse = 605 mm
* Eigengewicht = 5.400 kg
* Zul. Gesamtgewicht = 8.500 kg
==Bereifung==
'''Standardbereifung''' (Allrad)
* Vorne = 14.9-28 AS (2WD = 11.00-16)
* ''Niederquerschnitt:''
'''85''': 380/85R28
'''70''': 420/70R28, 480/70R26
'''65''': 480/65R28, 540/65R26
* Hinten = 20.8-38 AS
* ''Niederquerschnitt:''
'''85''': 520/85R38
'''70''': 580/70R38, 620/70R38
'''65''': 650/65R38, 750/65R34
'''Optional''' (Allrad)
* Vorne = 13.6-28 AS
* ''Niederquerschnitt:''
'''85''': 360/85R28
'''70''': 380/70R28, 420/70R28
'''65''': 440/65R28, 480/65R26
* Hinten = 18.4-38 AS
* ''Niederquerschnitt:''
'''85''': 460/85R38
'''70''': 520/70R38, 680/70R32
'''65''': 600/65R38
'''Pflegebereifung''' (Allrad)
* Vorne = 9.5-32 AS
* Hinten = 9.5-48 AS
==Füllmengen==
* Tankinhalt = '''155 l'''
* Mit optionalem Zusatztank = '''205 l'''
* ''Diesel''
* Motoröl inkl. Filter = '''16 l'''
* ''15W-40'', ''10W-30'' oder ''10W-40''
* ''Wechsel 200h/ 12 Monate''
* Hydraulik = '''18,5 l'''
* Mit optionalem Hydrauliktank: = '''38,5 l'''
* ''15W-40'' oder ''20W-20''
* ''Prüfen 250h, Wechsel 1000h/ 12 Monate''
* Getriebe inkl. Endantriebe = '''75 l'''
* ''15W-40'', ''80W-90 GL4'' oder ''10W-30''
* ''Wechsel 1000h/ 24 Monate''
* Vorderachse = '''9 l'''
* Endantriebe je = '''1L'''
* ''80W-90 GL5''
* ''Prüfen 500h, Wechsel 1000h/ 12 Monate''
==Verbrauch==
* Spezifischer Kraftstoffverbrauch bei Nennleistung = 237 g/kWh oder 174 g/PSh
* Optimaler Kraftstoffverbrauch = 216 g/kWh oder 159 g/PSh bei 82,5 kW und 1.650 U/min.
* Kraftstoffverbrauch mit Zapfwellen-Normdrehzahl (1.000 U/min.) = 246 g/kWh oder 181 g/PSh
==Kabine==
* Vollverglaste, gummigelagerte, staub- und schallisolierte (84 dB A) Deutz-Fahr-MasterCab-Kabine, Typ: SK 1905-37 mit ebenen Boden, Grammer-Komfort-Sitz, ausstellbarer Front-, Seiten- und Heckscheibe, dreistufen Heizungs- und Belüftungsgebläse, Traktormeter, Kraftstoffanzeige, Innen- und Außenspiegel und klappbarem Beifahrersitz
==Sonderausrüstung==
* Fronthydraulik
* Frontzapfwelle
* Klimaanlage
* Arbeitsscheinwerfer
* Frontlader
* Druckluftbremsanlage
* Zugpendel
* Super-Komfort-Sitz
* Zusatz-Steuergeräte
* Kriechgruppe
* Front-und Radgewichte
* Zusatz-Heizung
==Literatur==
* Hummel,Oertle: Typenkompass Deutz-Traktoren seit 1978, Motor-Buch-Verlag
* Vom DX bis zum Agrostar (Karel Vermoesen/Michael Bruse) Seite 580
* Technische Daten für Deutz-Fahr-Traktoren (Ausgabe 09/1983) Seiten 78-82
==Quellen==
* Hummel,Oertle: Typenkompass Deutz-Traktoren seit 1978, Motor-Buch-Verlag
<references />
==Weblinks==
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Deutz-Fahr |HERSTELLER= Deutz-Fahr}}
4qmp65mg6qpmd2mboj1a7hquhyvkpoc
Traktorenlexikon: Deutz-Fahr DX 140
0
88187
1090618
1090556
2026-09-09T12:14:10Z
JaWa1998
115962
1090618
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Deutz-Fahr |HERSTELLER= Deutz-Fahr}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = Deutz
| MODELLREIHE = DX-Reihe
| MODELL = DX 140
| BILD = DEUTZ DX140.jpg
| BILDBESCHREIBUNG = Deutz DX 140
| BAUWEISE = Blockbauweise
| PRODUKTIONSBEGINN = 1978
| PRODUKTIONSENDE = 1980
| STÜCKZAHL =
| EIGENGEWICHT = 5.400 (A: 5.860)
| LÄNGE = 4.716
| BREITE = 2.370
| HÖHE = 2.790
| RADSTAND = 2.831 (A: 2.826)
| BODENFREIHEIT = 620 (A: 480)
| SPURWEITE =
| SPURWEITE VORNE = 1.596-2.196 (A: 1.800/2.000)
| SPURWEITE HINTEN = 1.800-2.200
| WENDERADIUS MIT LENKBREMSE = 4.470
| WENDERADIUS OHNE LENKBREMSE = 4.970 (A: 6.340)
| BEREIFUNG VORNE = 11.00-16 ASF (A: 14.9-28 AS)
| BEREIFUNG HINTEN = 18.4-38 AS
| LEISTUNG KW = 91,5
| LEISTUNG PS = 125
| NENNDREHZAHL = 2.200
| ZYLINDER = 6
| HUBRAUM = 6.125
| DREHMOMENTANSTIEG = 20
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Luftkühlung
| ANTRIEBSTYP = Heck-oder Allradradantrieb
| GETRIEBE = 12V/4R, 24V/8R, 36V/12R
| HÖCHSTGESCHWINDIGKEIT = 25/30
| KATEGORIESORTIERUNG = Standardtraktor
}}
Der '''Deutz DX 140''' gehört zur '''1978''' eingeführten, neu entwickleten '''DX-Serie''' von Deutz. Er war direkt ab Marktstart erhältlich (gehört somit zur 1. Generation) und stellte dabei das zweitstärkste Modell der DX-Serie dar. Sein Vorgänger war das damalige Top-Modell [[Traktorenlexikon: Deutz D 13006|D 13006]] der Serie 06. Der DX 140 wurde allerdings mit dem neuen, turbo-aufgeladenen '''BF6L913'''-Motor mit 125PS ausgestattet. Da ZF das im Vorgänger verwendete Getriebe T-3402 ersatzlos entfallen lies und Deutz für den Leistungsbereich oberhalb von 120PS noch kein eigenes Getriebe entwickelt hatte, ging KHD eine Zusammenarbeit mit dem österreichischen Hersteller '''STEYR''' ein. Der DX 140 nutzte das Steyr-Triebwerk '''TW1200''' mit 2-facher, bei Deutz '''"Powermatic"''' genannten Lastschaltung, die über zwei Druckknöpfe im Armaturenbrett bedient wurde.
Die Anordnung des Steyr-Triebwerks entsprach dem des TW90-Triebwerks, allerdings mit nur vier Gängen. Um das Lastschaltgetriebe in einer 25 km/h sowie einer 30 km/h-Variante anbieten zu können, musste die Gesamtübersetzung angepasst werden. Leider entwickelte sich die Ersatzteilversorgung mit den Jahren problematisch.
Beim DX 140 wurde die '''MasterCab'''-Kabine serienmäßig angeboten. Zur Allrad-Variante bot Deutz auch eine Hinterradantrieb-Variante an, die aber ausschließlich für den Export bestimmt war.
Nach nur 2 Jahren Bauzeit wurde der '''DX 140''' 1980 durch seinen 7PS stärkeren Nachfolger [[Traktorenlexikon: Deutz-Fahr DX 145|DX 145]] ersetzt.
==Motor==
* KHD, Typ: BF6L 913, stehender-luftgekühlter Viertakt-Sechszylinder-Reihen-Turbomotor mit Direkteinspritzverfahren, Bosch-Reihen-Einspritzpumpe, Kolbenkühlung, Bosch-Vierloch-Düse, Dralleinspritzkanal, Trockenluftfilter mit Zyklon-Vorabscheider, hängenden Ventilen, Dreiring-Leichtmetall-Kolben, siebenfach-gelagerter Kurbelwelle, Bosch-Fliehkraft-Verstellregler, zahnradgetriebener Nockenwelle, Einzel-Aluminium-Zylinderköpfe, Druckumlaufschmierung mittel Zahnradpumpe, integrierter Motorölkühlung, Bosch-Kraftstoffpumpe, KKK-Abgas-Turbolader und Axial-Regelgebläse.
* Bohrung = 102 mm, Hub = 125 mm
* Hubraum = 6.125 cm³
* Drehmomentanstieg = 20%
* Verdichtungsverhältnis = 15,5:1
* Drehmoment bei Höchstleistung = 401 Nm
* Max. Drehmoment = 483 Nm bei 1.499 U/min.
* Leerlaufdrehzahl = 600 bis 750 U/min.
* Geregelter Drehzahlbereich = 700 bis 2.320 U/min.
* Max. Einspritzdruck = 175 + 8 bar
* Einspritzmenge = 67 mm³/Hub und Nenndrehzahl
* Ladedruck = 440 mbar
* Bosch-Kraftstoffpumpe, Typ: FB/KS 22 AD 23/2
* Bosch-Drehzahlregler, Typ: EP/RSV 325-1150 A 8 B 2020 D
* Bosch-Einspritzpumpe, Typ: PES 6 A 85 D 410 RS 2537
* Bosch-Mehrloch-Düse, Typ: DLLA 149 S 490
* Kühnle, Kopp und Kausch-Turbolader, Typ: 3 LEP 229 A/13.2
==Kupplung==
* trockene Einfachkupplung
* Pedal betätigt
* 350 mm Durchmesser
* Typ: LuK 350 DGFP
==Getriebe==
'''Merkmale'''
* Im Ölbad laufendes Steyr-Getriebe, Typ: '''STEYR TW 1200''' mit Seitenschaltung
* Vollynchronisiertes Wechselgetriebe mit vier Gängen
* Auf Wunsch Vorschaltgetriebe als zweistufige Lastschaltung zur Verdoppelung der Ganganzahl ('''DEUTZ-POWERMATIC''')
* Gruppen-Getriebe mit drei Vorwärts- und einer Rückwärtsgruppe, in die Bereiche L-M-H und R unterteilt
* Gruppen L und H mit Klauenschaltung
* Gruppen M und R mit Synchronschaltung
'''Eigenschaften'''
* Gangzahl vorwärts/rückwärts = 12/4
* Auf Wunsch mit '''DEUTZ-POWERMATIC''' = 24/8
* Auf Wunsch mit '''DEUTZ-POWERMATIC''' und Kriechgängen = 36/12
'''Gesamtübersetzung der Lastschaltstufe in Stellung "HI"'''
"Gruppe-L"
* 1.Gang = 274,18:1
* 2.Gang = 195,26:1
* 3.Gang = 141,72:1
* 4.Gang = 101,75:1
"Gruppe-M"
* 1.Gang = 164,73:1
* 2.Gang = 117,31:1
* 3.Gang = 85,15:1
* 4.Gang = 61,30:1
"Gruppe-H"
* 1.Gang = 75,45:1
* 2.Gang = 53,73:1
* 3.Gang = 39,00:1
* 4.Gang = 28,00:1
"Gruppe-R"
* 1.Gang = 158,62:1
* 2.Gang = 112,96:1
* 3.Gang = 81,99:1
* 4.Gang = 58,86:1
'''Gesamtübersetzung der Lastschaltstufe in Stellung "LO"'''
"Gruppe-L"
* 1.Gang = 344,02:1
* 2.Gang = 245,00:1
* 3.Gang = 177,82:1
* 4.Gang = 127,67:1
"Gruppe-M"
* 1.Gang = 206,69:1
* 2.Gang = 147,19:1
* 3.Gang = 106,83:1
* 4.Gang = 76,70:1
"Gruppe-H"
* 1.Gang = 94,67:1
* 2.Gang = 67,42:1
* 3.Gang = 48,93:1
* 4.Gang = 35,13:1
"Gruppe-R"
* 1.Gang = 199,02:1
* 2.Gang = 141,74:1
* 3.Gang = 102,87:1
* 4.Gang = 73,86:1
'''Optionale Kriechgruppe'''
"Gruppe-L"
* 1.Gang = 2315,33:1
* 2.Gang = 1648,89:1
* 3.Gang = 1196,77:1
* 4.Gang = 859,22:1
"Gruppe-M"
* 1.Gang = 1391,03:1
* 2.Gang = 990,64:1
* 3.Gang = 719,01:1
* 4.Gang = 516,21:1
"Gruppe-H"
* 1.Gang = 637,14:1
* 2.Gang = 453,75:1
* 3.Gang = 329,33:1
* 4.Gang = 236,44:1
"Gruppe-R"
* 1.Gang = 1339,45:1
* 2.Gang = 953,90:1
* 3.Gang = 692,35:1
* 4.Gang = 497,07:1
==Geschwindigkeiten vor- und rückwärts==
''Geschwindigkeiten mit Bereifung 18.4-38 AS''
'''25 km/h-Variante'''
"Gruppe-L"
* 1.Gang Stufe-LO = 2,0 km/h
* 1.Gang Stufe-HI = 2,5 km/h
* 2.Gang Stufe-LO = 2,8 km/h
* 2.Gang Stufe-HI = 3,5 km/h
* 3.Gang Stufe-LO = 3,8 km/h
* 3.Gang Stufe-HI = 4,8 km/h
* 4.Gang Stufe-LO = 5,3 km/h
* 4.Gang Stufe-HI = 6,7 km/h
"Gruppe-M"
* 1.Gang Stufe-LO = 3,3 km/h
* 1.Gang Stufe-HI = 4,1 km/h
* 2.Gang Stufe-LO = 4,6 km/h
* 2.Gang Stufe-HI = 5,8 km/h
* 3.Gang Stufe-LO = 6,4 km/h
* 3.Gang Stufe-HI = 8,0 km/h
* 4.Gang Stufe-LO = 8,9 km/h
* 4.Gang Stufe-HI = 11,1 km/h
"Gruppe-H"
* 1.Gang Stufe-LO = 7,2 km/h
* 1.Gang Stufe-HI = 9,0 km/h
* 2.Gang Stufe-LO = 10,0 km/h
* 2.Gang Stufe-HI = 12,7 km/h
* 3.Gang Stufe-LO = 13,9 km/h
* 3.Gang Stufe-HI = 17,4 km/h
* 4.Gang Stufe-LO = 19,4 km/h
* 4.Gang Stufe-HI = 25,0 km/h
"Gruppe-R"
* 1.Gang Stufe-LO = 3,4 km/h
* 1.Gang Stufe-HI = 4,3 km/h
* 2.Gang Stufe-LO = 4,8 km/h
* 2.Gang Stufe-HI = 6,0 km/h
* 3.Gang Stufe-LO = 6,6 km/h
* 3.Gang Stufe-HI = 8,3 km/h
* 4.Gang Stufe-LO = 9,2 km/h
* 4.Gang Stufe-HI = 11,6 km/h
'''30 km/h-Variante'''
"Gruppe-L"
* 1.Gang Stufe-LO = 2,3 km/h
* 1.Gang Stufe-HI = 2,9 km/h
* 2.Gang Stufe-LO = 3,3 km/h
* 2.Gang Stufe-HI = 4,1 km/h
* 3.Gang Stufe-LO = 4,5 km/h
* 3.Gang Stufe-HI = 5,7 km/h
* 4.Gang Stufe-LO = 6,2 km/h
* 4.Gang Stufe-HI = 7,9 km/h
"Gruppe-M"
* 1.Gang Stufe-LO = 3,9 km/h
* 1.Gang Stufe-HI = 4,9 km/h
* 2.Gang Stufe-LO = 5,5 km/h
* 2.Gang Stufe-HI = 6,8 km/h
* 3.Gang Stufe-LO = 7,5 km/h
* 3.Gang Stufe-HI = 9,4 km/h
* 4.Gang Stufe-LO = 10,5 km/h
* 4.Gang Stufe-HI = 13,1 km/h
"Gruppe-H"
* 1.Gang Stufe-LO = 8,5 km/h
* 1.Gang Stufe-HI = 10,6 km/h
* 2.Gang Stufe-LO = 11,9 km/h
* 2.Gang Stufe-HI = 14,9 km/h
* 3.Gang Stufe-LO = 16,4 km/h
* 3.Gang Stufe-HI = 20,6 km/h
* 4.Gang Stufe-LO = 22,8 km/h
* 4.Gang Stufe-HI = 30,0 km/h
"Gruppe-R"
* 1.Gang Stufe-LO = 3,4 km/h
* 1.Gang Stufe-HI = 4,3 km/h
* 2.Gang Stufe-LO = 4,8 km/h
* 2.Gang Stufe-HI = 6,0 km/h
* 3.Gang Stufe-LO = 6,6 km/h
* 3.Gang Stufe-HI = 8,3 km/h
* 4.Gang Stufe-LO = 9,2 km/h
* 4.Gang Stufe-HI = 11,6 km/h
'''Optionale Kriechgruppe'''
"Gruppe-L"
* 1.Gang = 0,31 km/h
* 2.Gang = 0,43 km/h
* 3.Gang = 0,59 km/h
* 4.Gang = 0,83 km/h
"Gruppe-M"
* 1.Gang = 0,51 km/h
* 2.Gang = 0,72 km/h
* 3.Gang = 0,99 km/h
* 4.Gang = 1,37 km/h
"Gruppe-H"
* 1.Gang = 1,11 km/h
* 2.Gang = 1,56 km/h
* 3.Gang = 2,15 km/h
* 4.Gang = 3,00 km/h
"Gruppe-R"
* 1.Gang = 0,53 km/h
* 2.Gang = 0,74 km/h
* 3.Gang = 1,02 km/h
* 4.Gang = 1,43 km/h
==Zapfwelle==
* Unabhängige Motorzapfwelle
* Elektrohydraulisch betätigt und lastschaltbar
* 1.000/min b. Motordrehzahl 1.920/min
* Übertragbare Leistung = 82,4 kW ~ 112 PS
* Stummel = 1 3/8" - 21-teilig (Form-B)
==Bremsen==
'''Betriebsbremse'''
* hydraulisch betätigte, nasse GIRLING-Vollscheibenbremse
* Auf die Differentialseitenwellen wirkend, als Einzelrad-Bremse zu verwenden
* Lamellen-Bremse mit sechs Belagscheiben, je eine links und rechts mit 222 mm Durchmesser
'''Feststellbremse'''
* Unabhängige, mechanisch betätigte Feststellbremse
* Auf die Betriebsbremse wirkend
* Auf Wunsch auf eigene Belagscheiben wirkend
'''Verzögerungswerte'''
* Max. Verzögerung = 3,9 m/s²
* Pedalkraft = 25 daN
* Bremsweg bei 25 km/h = 7,8 m
'''Optional'''
* Zweikreis-Druckluftbremsanlage
* Kombinierte Ein-und Zweikreis-Druckluftbremsanlage
==Achsen==
'''Vorderachsen'''
''Bei Hinterradantrieb (2WD)''
* Pendelnd-gelagerte Teleskop-Vorderachse, Typ: '''KHD Tele-03'''
* Spurweite sechsfach-verstellbar in Stufen von 100 mm = 1.596 bis 2.196 mm
''Bei Allradantrieb (4WD)''
* pendelnd-gelagerte, elektrohydraulisch-betätigte und lastschaltbare ZF-Lenktriebachse, Typ: '''ZF APL-3052''' mit seitlicher Gelenkwelle
* Übersetzungsverhältnis = '''1,346'''
* Spurweiten durch Radumschlag = 1.800 oder 2.000 mm
'''Hinterachse'''
* Hinterachse mit Kegelradgetriebe, Tellerrad und Planetengetriebe
* Vierfache Spurverstellung durch Radumschlag und Radscheiben, in Stufen von 100 mm = 1.600 bis 2.200 mm
* Pedal betätigte, selbstausrückende und lastschaltbare Differentialsperre
'''Achslasten'''
''bei Allradantrieb''
* Vorderachslast = 2.285 kg (2WD = 1.835 kg)
* Zul. Vorderachslast = 3.200 kg (2WD = 2.800 kg)
* Hinterachslast = 3.575 kg (2WD = 3.565 kg)
* Zul. Hinterachslast = 6.300 kg
==Lenkung==
'''Lenkanlage'''
* Hydrostatische ZF-Lenkung, Typ: '''ZF Servostat 8452''' mit eigenem Ölkreislauf
* Lenkzylinder mit 50 mm Kolbendurchmesser und 250 mm Kolbenhub
'''Hydraulische Versorgung'''
* Bosch-Pumpe, Typ: HY/ZFS 11/19 L
* Förderleistung je Pumpenumdrehung = 19 cm³
* Fördermenge = 45 l/min.
==Hydrauliksystem und Kraftheber==
'''Kraftheber'''
* DEUTZ-TRANSFERMATIC-SYSTEM K55.2 mit 2 Zusatzhubzylindern mit Unterlenkerregelung
* Pumpenantrieb direkt vom Getriebe
* Dreipunktkupplung = Kat. II (Wunsch Kat. III)
* Zusatzsteuergeräte = max. 3
'''Funktionen'''
* Heben, Senken, Neutral- und Schwimmstellung, Lage- und Zugkraftregelung
* Hubhöhenbegrenzung, Seitenstabilisierung und Transportsicherung
'''Hydraulische Versorgung'''
* Bosch-Zahnradpumpe, Typ: HY/ZFS 11/22,5 l
* Förderleistung je Pumpenumdrehung = 22,5 cm³
* Fördermenge = 58,5 l/min
* Arbeitsdruck = 175 bar
'''Leistung'''
* Leistung der Hydraulik = 16,2 kW
* Max. Hubkraft an den Koppelpunkten = 63.800N (6.500kp ~ 6.500kg)
==Steuergeräte==
* 1 DW Steuergerät
* Optional bis zu zwei weitere EW oder DW Zusatz-Steuergeräte
==Elektrische Ausrüstung==
* 12 Volt-Einrichtung nach StVZO
* Batterie, 12 V-143 Ah
* Bosch-Anlasser, ID 12 V-3 kW
* Bosch-Lichtmaschine mit integriertem Regler, G1 14 V-65 A
* Kaltstart-Flammglühkerze, B 12 VH 7632
==Maße und Abmessungen==
'''Allrad'''
* Bei Bereifung vorn/hinten = 14.9-28/20.8-38
* Radstand = 2.826 mm
* Länge = 4.716 mm
* Breite = 2.370 mm
* Höhe über Auspuff = 2.920 mm
* Höhe über offene Auspuffklappe = 3.050 mm
* Bodenfreiheit unter Allradachse = 480 mm
* Spurweiten vorn = 1.800 u. 2.000 mm
* Spurweiten hinten = (1.600) 1.700 ... 2.200 mm
* Wenderadius o. Lenkbremse = 6.340 mm
* Leergewicht = 5.750 kg
* Zul. Gesamtgewicht = 8.000 kg
'''Geänderte Werte durch Hinterradantrieb-Ausführung'''
* Bodenfreiheit unter der Teleskop-Achse = 620 mm
* Eigengewicht = 5.400 kg
* Zul. Gesamtgewicht = 7.700 kg
==Bereifung==
'''Standardbereifung''' (Allrad)
* Vorne = 14.9-28 AS (2WD = 11.00-16)
* ''Niederquerschnitt:''
'''85''': 380/85R28
'''70''': 420/70R28, 480/70R26
'''65''': 480/65R28, 540/65R26
* Hinten = 20.8-38 AS
* ''Niederquerschnitt:''
'''85''': 520/85R38
'''70''': 580/70R38, 620/70R38
'''65''': 650/65R38, 750/65R34
'''Optional''' (Allrad)
* Vorne = 13.6-28 AS
* ''Niederquerschnitt:''
'''85''': 360/85R28
'''70''': 380/70R28, 420/70R28
'''65''': 440/65R28, 480/65R26
* Hinten = 18.4-38 AS
* ''Niederquerschnitt:''
'''85''': 460/85R38
'''70''': 520/70R38, 680/70R32
'''65''': 600/65R38
'''Pflegebereifung''' (Allrad)
* Vorne = 9.5-32 AS
* Hinten = 9.5-48 AS
==Füllmengen==
* Tankinhalt = '''155 l'''
* Mit optionalem Zusatztank = '''205 l'''
* ''Diesel''
* Motoröl inkl. Filter = '''16 l'''
* ''15W-40'', ''10W-30'' oder ''10W-40''
* ''Wechsel 200h/ 12 Monate''
* Hydraulik = '''18,5 l'''
* Mit optionalem Hydrauliktank: = '''38,5 l'''
* ''15W-40'' oder ''20W-20''
* ''Prüfen 250h, Wechsel 1000h/ 12 Monate''
* Getriebe inkl. Endantriebe = '''75 l'''
* ''15W-40'', ''80W-90 GL4'' oder ''10W-30''
* ''Wechsel 1000h/ 24 Monate''
* Vorderachse = '''9 l'''
* Endantriebe je = '''1L'''
* ''80W-90 GL5''
* ''Prüfen 500h, Wechsel 1000h/ 12 Monate''
==Verbrauch==
* Optimaler Kraftstoffverbrauch = 216 g/kWh bzw. 160g/PSh bei Mmax
* ca. 16,8L/h bei 125PS
==Kabine==
* Vollverglaste, gummigelagerte, staub- und schallisolierte (85 dB(A)) Deutz-MasterCab-Kabine mit ebenen Boden, Grammer-Komfort-Sitz, ausstellbare Front- und Heckscheibe, dreistufen Heizung- und Belüftungsgebläse mit 7 Düsen, Traktormeter, Analog-Uhr, Motortemperaturanzeige, Kraftstoffanzeige, Kontrollleuchten und klappbarem Beifahrersitz.
==Sonderausrüstung==
* Kriechgruppe
* Front- und Radgewichte
* Frontlader
* Druckluftbremsanlage mit Druckmanometer im Armaturenbrett
* Zusatz-Heizung
* Arbeitsscheinwerfer
* Klimaanlage
* Zusatz-Tank
* Zusatz-Steuergeräte
* Zugpendel
==Literatur==
* Vom DX zum Agrostar (Karel Vermoesen/Michael Bruse) Seite 576
* Deutz-Das Typenbuch (Albert Mößmer)
* Vom MTH zum Agrotron (Bernd Ertl)
==Quellen==
<references />
==Weblinks==
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Deutz-Fahr |HERSTELLER= Deutz-Fahr}}
m2iy6bojxz1i1lhopvwmia9kgj67d3n
Vokabeltexte Chinesisch/ Vokabellektionen/ Lektion 561
0
100981
1090624
1014074
2026-09-09T14:09:29Z
Christian-bauer
6469
kleinere Ergänzungen und Korrekturen
1090624
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor|
zurücktext=Lektion 560|
zurücklink=Vokabeltexte_Chinesisch/_Vokabellektionen/ Lektion 560|
hochtext=Buch Vokabellektionen|
hochlink=Vokabeltexte_Chinesisch/_Vokabellektionen|
vortext=Lektion 562|
vorlink=Vokabeltexte_Chinesisch/_Vokabellektionen/ Lektion 562}}
</noinclude>
== Zeichen ==
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung !! Lernhilfen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势}} || shi4 || Kraft, Einfluß, Potential, Moment, Trend, Zeichen, Geste, männliche Geschlechtsorgane, Situation, Lage || {{:Vokabeltexte_Chinesisch/ Vorlage:Texte_Zeichen_Externe_Links|Zeichen=势}}
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |攫}} || jue2 || ergreifen || {{:Vokabeltexte_Chinesisch/ Vorlage:Texte_Zeichen_Externe_Links|Zeichen=攫}}
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |鸷}} || zhi4 || Raubvögel, räuberisch || {{:Vokabeltexte_Chinesisch/ Vorlage:Texte_Zeichen_Externe_Links|Zeichen=鸷}}
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛}} || meng3 || plötzlich, unerwartet, schlagartig, jäh, abrupt, wild, heftig, kräftig,wuchtig, ungestüm || {{:Vokabeltexte_Chinesisch/ Vorlage:Texte_Zeichen_Externe_Links|Zeichen=猛}} (HSK 3.0 Band 6)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦}} || she4 || verzeihen, begnadigen || {{:Vokabeltexte_Chinesisch/ Vorlage:Texte_Zeichen_Externe_Links|Zeichen=赦}}
|}
== Zusammengesetzte Wörter ==
=== 势 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung !! Lernhilfen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |架势}} || jia4 shi4 || <geh> Lage, Positur, <umg> Getue, Gehabe ||(HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势力}} || shi4 li4 || Macht, Potenz, Rettungskraft || (HSK 3.0 Band 5)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |去势}} || qu4 shi4 || Entmannung, Kastrierung, Wallach, kastrieren, kastriert(Adj, Med)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势能}} || shi4 neng2 || potenzielle Energie
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势子}} || shi4 zi5 || Gestalt, Geste, Haltung, Umstände, männliches Glied
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |电势}} || dian4 shi4 || elektrisches Potential
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |就势}} || jiu4 shi4 || sich die Umstände, die Gelegenheit zu Nutze machen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |态势}} || tai4 shi4 || Lage, Situation
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |火势}} || huo3 shi4 || Feuer, Flammenmeer
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |风势}} || feng1 shi4 || Situation < metaphorisch >, Windsituation, Windstärke
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势态}} || shi4 tai4 || Stellung Posten
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |仗势}} || zhang4 shi4 || sich auf eine Machtposition stützen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |起势}} || qi3 shi4 || Anfangsschritt
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势炒}} || shi4 chao3 || Machtgerangel
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |长势}} || zhang3 shi4 || Wachstum, Entwicklungsstand
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |强势}} || qiang2 shi4 || mächtig || (HSK 3.0 Band 6)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |威势}} || wei1 shi4 || kann
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |欢势}} || huan1 shi5 || quirlig
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |走势}} || zou3 shi4 || Tendenz, Entwicklung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |乘势}} || cheng2 shi4 || die Gunst der Stunde nutzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |优势}} || you1 shi4 || Stärke, Überlegenheit, Übermacht, Oberhand, Oberwasser || (HSK 3.0 Band 3)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势至}} || shi4 zhi4 || Bodhisattva Mahāsthāmaprapta
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |运势}} || yun4 shi4 || Horoskop
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |情势}} || qing2 shi4 || Situation
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势必}} || shi4 bi4 || zwangsläufig || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |把势}} || ba3 shi5 || Meister; Können; chinesische Kampfkunst
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势头}} || shi4 tou2 || Stärke, Schwung, Macht, Wucht, Tendenz || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |时势}} || shi2 shi4 || aktuelle Lage
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |手势}} || shou3 shi4 || Geste || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |气势}} || qi4 shi4 || Imposanz, Schwung, Wucht || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势利}} || shi4 li4 || eingebildet und kriecherisch
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |伤势}} || shang1 shi4 || Grade der Verletzung, Verletzung, Verletzungsgrad || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |大势}} || da4 shi4 || allgemeine Tendenz
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |弱势}} || ruo4 shi4 || in (relativ) schwacher Position, negativer Trend, im Abwind sein || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |收势}} || shou1 shi4 || Schlussschritt
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |均势}} || jun1 shi4 || Balance of Power, Beharrungszustand, Gegengewicht, Gleichgewicht
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |作势}} || zuo4 shi4 || sich in Positur setzen, ein geziertes Gehabe an den Tag leben
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |权势}} || quan2 shi4 || Macht und Einfluss
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |阵势}} || zhen4 shi4 || Lage (militärische, strategisch), Situation (militärische, strategisch)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |水势}} || shui3 shi4 || Wasserverhältnisse, Zustand des Wassers
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |李势}} || li3 shi4 || Li Shi
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |形势}} || xing2 shi4 || Situation, Lage, Umstände, Verhältnisse, topographische Lage, Terrain || (HSK 3.0 Band 4)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |守势}} || shou3 shi4 || defensiv
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |失势}} || shi1 shi4 || Macht und Einfluß verlieren
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |局势}} || ju2 shi4 || Situation || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |声势}} || sheng1 shi4 || Impuls, Moment
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |体势}} || ti3 shi4 || Einrichtung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |顺势}} || shun4 shi4 || eine Gelegenheit geistesgegenwärtig ausnutzen || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |东势镇}} || dong1 shi4 zhen4 || Tungshih (Ort in Taiwan)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |伊势国}} || yi1 shi4 guo2 || Provinz Ise
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |地势图}} || di4 shi4 tu2 || topographische Karte
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |电动势}} || dian4 dong4 shi4 || EMK, elektromotorische Kraft
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |占优势}} || zhan4 you4 shi4 || Aszendent, überwiegen, dominieren, prädominieren, vorherrschen, vorwiegen, überwiegend, dominant, einflussreich
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势利眼}} || shi4 li5 yan3 || kriecherisch und eingebildet, devot und snobistisch
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |方位势}} || fang1 wei4 shi4 || Kastenpotential
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |东势乡}} || dong1 shi4 xiang1 || Tungshih (Dorf in Taiwan)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |身势学}} || shen1 shi4 xue2 || Kinesik
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |优势种}} || you1 shi4 zhong3 || emporragend
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |大势至}} || da4 shi4 zhi4 || Bodhisattva Mahāstānaprapta
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |化学势}} || hua4 xue2 shi4 || Chemisches Potential
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |被去势}} || bei4 qu4 shi4 || wurde kastriert, kastriert
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |位势论}} || wei4 shi4 lun4 || Potentialtheorie
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |必然局势}} || bi4 ran2 ju2 shi4 || zwangsläufige Tendenz
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |有钱有势}} || you3 qian2 you3 shi4 || Geld und Macht besitzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |业务形势}} || ye4 wu4 xing2 shi4 || Geschäftsbedingung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势所必然}} || shi4 suo3 bi4 ran2 || ganz selbstverständlich
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |采取守势}} || cai3 qu3 shou3 shi4 || Defensive ergreifen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |优势地位}} || you4 shi4 di4 wei4 || Vorherrschaft
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势如破竹}} || shi4 ru2 po4 zhu2 || mächtig, beeindruckend
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |力量均势}} || li4 liang4 jun1 shi4 || Gleichgewicht der Kräfte
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |有权势者}} || you3 quan2 shi4 zhe3 || Potentat
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |绝对优势}} || jue2 dui4 you4 shi4 || absoluter Kostenvorteil
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |比较优势}} || bi3 jiao4 you1 shi4 || Komparativer Kostenvorteil(Wirtsch)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |价格优势}} || jia4 ge2 you4 shi4 || Preisvorteil
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势在必行}} || shi4 zai4 bi4 xing2 || (English: be required by circumstances), gezwungenermaßen, jm. bleibt nichts anderes übrig
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势不两立}} || shi4 bu4 liang3 li4 || Todfeinde sein
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |经济形势}} || jing1 ji4 xing2 shi4 || Geschäftsklima, Konjunkturlage, Wirtschaftslage
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |就业形势}} || jiu4 ye4 xing2 shi4 || Arbeitsmarktsituation
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |紧张局势}} || jin3 zhang1 ju2 shi4 || angespannte Lage
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |成本优势}} || cheng2 ben3 you1 shi4 || Kostenvorteile
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |杂种优势}} || za2 zhong3 you1 shi4 || Heterosis-Effekt
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |伊势神宫}} || yi1 shi4 shen2 gong1 || Ise-jingū(Philos)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势不可挡}} || shi4 bu4 ke3 dang4 || unaufhaltsam
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |有权有势}} || you3 quan2 you3 shi4 || Macht und Einfluß haben
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |人多势众}} || ren2 duo1 shi4 zhong4 || zahlenmäßig überlegen(Adj, Sprichw)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势力均衡}} || shi4 li4 jun1 heng2 || Machtgleichgewicht, Kräftegleichgewicht
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |市场优势}} || shi4 chang3 you1 shi4 || Wettbewerbsvorteil
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |有财有势}} || you3 cai2 you3 shi4 || wohlhabend und einflussreich
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |弱势群体}} || ruo4 shi4 qun2 ti3 || schwache Bevölkerungsschichten
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |因势利导}} || yin1 shi4 li4 dao3 || sein Handeln nach der Situation ausrichten
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |国际形势}} || guo2 ji4 xing2 shi4 || internationale Lage, Weltlage, zwischenstaatliche Angelegenheiten
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |安全形势}} || an1 quan2 xing2 shi4 || Sicherheitslage
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |去势的马}} || qu4 shi4 de5 ma3 || Wallach (kastriertes Pferd)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |安全局势}} || an1 quan2 ju2 shi4 || Sicherheitslage
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |有权势的人}} || you3 quan2 shi4 de5 ren2 || Mogul
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |标准化学势}} || biao1 zhun3 hua4 xue2 shi4 || chemisches Standardpotential
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |顺应时势者}} || shun4 ying4 shi2 shi4 zhe3 || Opportunist
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |去势的动物}} || qu4 shi4 de5 dong4 wu4 || kastrietes Tier
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |经济形势分析}} || jing1 ji4 xing2 shi4 fen1 xi1 || Konjunkturanalyse
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |经济上的优势}} || jing1 ji4 shang4 de5 you1 shi4 || wirtschaftlicher Vorsprung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |借别人的势力}} || jie4 bie2 ren2 de5 shi4 li4 || die Stärke anderer nutzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |经济形势期望}} || jing1 ji4 xing2 shi4 qi1 wang4 || Konjunkturerwartungen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |在困难局势下}} || zai4 kun4 nan5 ju2 shi4 xia4 || gedrückt
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |世界经济形势}} || shi4 jie4 jing1 ji4 xing2 shi4 || Weltkonjunktur
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |力优势协同作用}} || li4 you1 shi4 xie2 tong2 zuo4 yong4 || Synergie
|}
=== 攫 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |攫夺}} || jue2 duo2 || plündern
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |攫取}} || jue2 qu3 || entreißen, an sich reißen
|}
=== 鸷 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |阴鸷}} || yin1 zhi4 || malicious, treacherous
|}
=== 猛 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung !! Lernhilfen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |凶猛}} || xiong1 meng3 || wild || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛兽}} || meng3 shou4 || Raubtier
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛力}} || meng3 li4 || heftig; mit aller Kraft
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |狂猛}} || kuang2 meng3 || lautstark
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛击}} || meng3 ji1 || Ruck, ruckeln, schmettern, stanzen, zerschmettern
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛拉}} || meng3 la1 || Ruck, reißen, zerren, zupfen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛醒}} || meng3 xing3 || jäh erwachen, schlagartig begreifen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛然}} || meng3 ran2 || unvermittelt, plötzlich, schlagartig, abrupt || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛推}} || meng3 tui1 || stoßen, einen Stoß versetzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛咬}} || meng3 yao3 || kurz anberaumt
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |勇猛}} || yong3 meng3 || tapfer und kühn
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛打}} || meng3 da3 || stanzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛冲}} || meng3 chong1 || Nachnahme
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛压}} || meng3 ya1 || stanzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛扑}} || meng3 pu1 || sich auf etwas stürzen, sich auf jemanden stürzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |王猛}} || wang2 meng3 || Wang Meng
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛烈}} || meng3 lie4 || heftig, vehement, ungestüm || (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |生猛}} || sheng1 meng3 || unverbesserlicher Optimist
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛按}} || meng3 an4 || stanzen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛虎}} || meng3 hu3 || wilder Tiger
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛力关}} || meng3 li4 guan1 || (eine Tür) zuschlagen, zuwerfen, ins Schloss werfen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛力關}} || meng3 li4 guan1 || (traditionelle Schreibweise von 猛力关), (eine Tür) zuschlagen, zuwerfen, ins Schloss werfen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |下猛药}} || xia4 meng3 yao4 || Radikalkur
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |下猛藥}} || xia4 meng3 yao4 || (traditionelle Schreibweise von 下猛药), Radikalkur
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |洪水猛兽}} || hong2 shui3 meng3 shou4 || große und schlimme Plagen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |价格猛涨}} || jia4 ge2 meng3 zhang3 || Preissprung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛地一动}} || meng3 de5 yi1 dong4 || Ruck
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛地一動}} || meng3 de5 yi1 dong4 || (traditionelle Schreibweise von 猛地一动), Ruck
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |突飞猛进}} || tu2 fei1 meng3 jin4 || sich sprunghaft entwickeln
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |突飛猛進}} || tu2 fei1 meng3 jin4 || (traditionelle Schreibweise von 突飞猛进), sich sprunghaft entwickeln
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |威猛乐队}} || wei1 meng3 yue4 dui4 || Wham!
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |勇猛的人}} || yong3 meng3 de5 ren2 || Löwe
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛地一拉}} || meng3 de5 yi1 la1 || Ruck
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛龙过江}} || meng3 long2 guo4 jiang1 || The Way of the Dragon
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛然掉落}} || meng3 ran2 diao4 luo4 || Preissturz
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛然回抽}} || meng3 ran2 hui2 chou1 || Ruck
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |高歌猛进}} || gao1 ge1 meng3 jin4 || triumphierend voranschreiten
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |高歌猛進}} || gao1 ge1 meng3 jin4 || (traditionelle Schreibweise von 高歌猛进), triumphierend voranschreiten
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |尼米亚猛狮}} || ni2 mi3 ya4 meng3 shi1 || Nemeischer Löwe
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |尼米亞猛獅}} || ni2 mi3 ya4 meng3 shi1 || (traditionelle Schreibweise von 尼米亚猛狮), Nemeischer Löwe
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛狮股份公司}} || meng3 shi1 gu3 fen4 gong1 si1 || MAN AG
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛獅股份公司}} || meng3 shi1 gu3 fen4 gong1 si1 || (traditionelle Schreibweise von 猛狮股份公司), MAN AG
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |英国威猛乐队}} || ying1 guo2 wei1 meng3 yue4 dui4 || Wham!
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |多伦多猛龙队}} || duo1 lun2 duo1 meng3 long2 dui4 || Toronto Raptors
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |突飞猛进的发展}} || tu2 fei1 meng3 jin4 de5 fa1 zhan3 || rasante Entwicklung, rasche Entwicklung, dynamische Entwicklung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |突飛猛進的發展}} || tu2 fei1 meng3 jin4 de5 fa1 zhan3 || (traditionelle Schreibweise von 突飞猛进的发展), rasante Entwicklung, rasche Entwicklung, dynamische Entwicklung
|}
=== 赦 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦罪}} || she4 zui4 || Sünden verzeihen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦免}} || she4 mian3 || Amnestie
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |大赦}} || da4 she4 || Amnestie
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |特赦}} || te4 she4 || Amnestie, Begnadigung, begnadigen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦令}} || she4 ling4 || amnesty, pardon
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |宽赦}} || kuan1 she4 || to forgive
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |特赦令}} || te4 she4 ling4 || Amnestie(Rechtsw)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |不可赦}} || bu4 ke3 she4 || unverzeihlich
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |国际特赦}} || guo2 ji4 te4 she4 || Amnesty International
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |不宽赦免}} || bu4 kuan1 she4 mian3 || Unerbittlichkeit
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |予以特赦}} || yu3 yi3 te4 she4 || amnestieren, begnadigen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |大赦国际}} || da4 she4 guo2 ji4 || Amnesty International, AI
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |十恶不赦}} || shi2 e4 bu4 she4 || wicked beyond redemption, heinous
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |十惡不赦}} || shi2 e4 bu4 she4 || (traditionelle Schreibweise von 十恶不赦), wicked beyond redemption, heinous
|}
== Sätze ==
=== 势 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |两相比较,他那边的形势更不利一些。}} || liang3 xiang1/xiang4 bi4 jiao4 , ta1 na4/nei4 bian1 de5 xing2 shi4 geng4 bu4 li4 yi1 xie1 。|| Im Vergleich der beiden zog er den Kürzeren. (Mandarin, [https://tatoeba.org/eng/sentences/show/8845148 Tatoeba] [https://tatoeba.org/eng/user/profile/crescat crescat] [https://tatoeba.org/eng/user/profile/Yorwba Yorwba])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她充分利用她住在伦敦的优势,提高英语。}} || ta1 chong1 fen1 li4 yong4 ta1 zhu4 zai4 lun2 dun1 de5 you1 shi4 , ti2 gao1 ying1 yu3 。|| Sie nutzte ihren Londonaufenthalt voll aus, um ihr Englisch zu verbessern. (Mandarin, [https://tatoeba.org/eng/sentences/show/863949 Tatoeba] [https://tatoeba.org/eng/user/profile/kooler kooler] [https://tatoeba.org/eng/user/profile/Pfirsichbaeumchen Pfirsichbaeumchen])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |天行健,君子以自强不息。地势宽,君子以厚德载物。}} || tian1 hang2/xing2 jian4 , jun1 zi5 yi3 zi4 jiang4/qiang2/qiang3 bu4 xi1 。 de4/di4 shi4 kuan1 , jun1 zi5 yi3 hou4 de2 zai3/zai4 wu4 。|| Auch wenn die Natur unbeugsam ist, müssen wir uns bemühen. Auch wenn Mutter Erde tolerant ist, müssen wir tugendhaft handeln. (klassisch, [https://tatoeba.org/eng/sentences/show/1635583 Tatoeba] [https://tatoeba.org/eng/user/profile/hongsly hongsly])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |懂得用电脑是一种优势。}} || dong3 de2/de5/dei3 yong4 dian4 nao3 shi4 yi1 chong2/zhong3/zhong4 you1 shi4 。|| Es ist von Vorteil, Computer bedienen zu können. (Mandarin, [https://tatoeba.org/eng/sentences/show/1452251 Tatoeba] [https://tatoeba.org/eng/user/profile/nickyeow nickyeow] [https://tatoeba.org/eng/user/profile/xtofu80 xtofu80])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她的父母不能不担心她的伤势。}} || ta1 de5 fu4 mu3 bu4 neng2 bu4 担 xin1 ta1 de5 shang1 shi4 。|| Ihre Eltern konnten nicht anders, als sich Sorgen zu machen wegen ihrer Verletzungen. (Mandarin, [https://tatoeba.org/eng/sentences/show/2394593 Tatoeba] [https://tatoeba.org/eng/user/profile/fenfang557 fenfang557] [https://tatoeba.org/eng/user/profile/Tamy Tamy])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |他们很努力地超过对方获得优势。}} || ta1 men5 hen3 nu3 li4 de4/di4 chao1 guo4 dui4 fang1 huo4 de2/de5/dei3 you1 shi4 。|| They tried very hard to gain an advantage over one another. (Mandarin, [https://tatoeba.org/eng/sentences/show/830313 Tatoeba] [https://tatoeba.org/eng/user/profile/Martha Martha] [https://tatoeba.org/eng/user/profile/CK CK])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |在学校时我学了中文是个优势。}} || zai4 xue2 jiao4/xiao4 shi2 wo3 xue2 le5 zhong1/zhong4 wen2 shi4 ge4 you1 shi4 。|| Es war von Vorteil, während meiner Schulzeit Chinesisch gelernt zu haben. (Mandarin, [https://tatoeba.org/eng/sentences/show/335487 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/landano landano])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |多温柔的手势啊。}} || duo1 wen1 柔 de5 shou3 shi4 a1 。|| What a tender gesture. (Mandarin, [https://tatoeba.org/eng/sentences/show/9690004 Tatoeba] [https://tatoeba.org/eng/user/profile/iMaple iMaple] [https://tatoeba.org/eng/user/profile/Eccles17 Eccles17])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |主场队总是比对手有优势。}} || zhu3 chang3 dui4 zong3 shi4 bi4 dui4 shou3 you3 you1 shi4 。|| The home team always have an advantage over their opponents. (Mandarin, [https://tatoeba.org/eng/sentences/show/755897 Tatoeba] [https://tatoeba.org/eng/user/profile/U2FS U2FS] [https://tatoeba.org/eng/user/profile/CM CM])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她们用手势沟通。}} || ta1 men5 yong4 shou3 shi4 gou1 tong1 。|| Sie kommunizieren mit Gesten. (Mandarin, [https://tatoeba.org/eng/sentences/show/10323881 Tatoeba] [https://tatoeba.org/eng/user/profile/DaoSeng DaoSeng] [https://tatoeba.org/eng/user/profile/Zaghawa Zaghawa])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |你受过良好教育,这是你的优势。}} || ni3 shou4 guo4 liang2 hao3 jiao1 yu4 , zhe4/zhei4 shi4 ni3 de5 you1 shi4 。|| Du hast den Vorteil einer guten Bildung. (Mandarin, [https://tatoeba.org/eng/sentences/show/342853 Tatoeba] [https://tatoeba.org/eng/user/profile/nickyeow nickyeow] [https://tatoeba.org/eng/user/profile/Zaghawa Zaghawa])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |人们在美国使用这些手势吗?}} || ren2 men5 zai4 mei3 guo2 shi3/shi4 yong4 zhe4/zhei4 xie1 shou3 shi4 ma5 ?|| Do people in America use these gestures? (Mandarin, [https://tatoeba.org/eng/sentences/show/759761 Tatoeba] [https://tatoeba.org/eng/user/profile/Martha Martha] [https://tatoeba.org/eng/user/profile/sharris123 sharris123])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她给我打了一个看不懂的手势。}} || ta1 gei3 wo3 da3 le5 yi1 ge4 kan4 bu4 dong3 de5 shou3 shi4 。|| She gave me a hand gesture I didn't understand. (Mandarin, [https://tatoeba.org/eng/sentences/show/4764877 Tatoeba] [https://tatoeba.org/eng/user/profile/ryanwoo ryanwoo] [https://tatoeba.org/eng/user/profile/garborg garborg])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |昨晚雨势很大。}} || zuo2 wan3 yu3 shi4 hen3 da4 。|| Wir hatten einen starken Regenfall gestern Nacht. (Mandarin, [https://tatoeba.org/eng/sentences/show/796072 Tatoeba] [https://tatoeba.org/eng/user/profile/Martha Martha] [https://tatoeba.org/eng/user/profile/Esperantostern Esperantostern])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |汤姆有一点势利。}} || tang1 mu3 you3 yi1 dian3 shi4 li4 。|| Tom is a bit snobbish. (Mandarin, [https://tatoeba.org/eng/sentences/show/8794701 Tatoeba] [https://tatoeba.org/eng/user/profile/slo_oth slo_oth] [https://tatoeba.org/eng/user/profile/CK CK])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |最近这个区域的国际形势很紧张。}} || zui4 jin4 zhe4/zhei4 ge4 qu1 yu4 de5 guo2 ji4 xing2 shi4 hen3 jin3 zhang1 。|| Recently, this area's international relations have become very tense. (Mandarin, [https://tatoeba.org/eng/sentences/show/6031658 Tatoeba] [https://tatoeba.org/eng/user/profile/xjjAstrus xjjAstrus] [https://tatoeba.org/eng/user/profile/sharris123 sharris123])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |花子虚张声势。}} || hua1 zi5 xu1 zhang1 sheng1 shi4 。|| Hanako forderte ihn auf, Farbe zu bekennen. (Mandarin, [https://tatoeba.org/eng/sentences/show/917992 Tatoeba] [https://tatoeba.org/eng/user/profile/Martha Martha] [https://tatoeba.org/eng/user/profile/Tickler Tickler])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |我对她做了一个手势,叫她坐下。}} || wo3 dui4 ta1 zuo4 le5 yi1 ge4 shou3 shi4 , jiao4 ta1 zuo4 xia4 。|| Ich bedeutete ihr, Platz zu nehmen. (Mandarin, [https://tatoeba.org/eng/sentences/show/492885 Tatoeba] [https://tatoeba.org/eng/user/profile/nickyeow nickyeow] [https://tatoeba.org/eng/user/profile/al_ex_an_der al_ex_an_der])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |融化中的极地冰盖也可以使海平面上涨的势态更加严重。}} || rong2 hua4 zhong1/zhong4 de5 ji2 de4/di4 bing1 gai4 ye3 ke3/ke4 yi3 shi3/shi4 hai3 ping2 mian4 shang4 zhang3 de5 shi4 tai4 geng4 jia1 yan2 chong2/zhong4 。|| Melting polar icecaps could also contribute to an increase in sea levels. (Mandarin, [https://tatoeba.org/eng/sentences/show/727334 Tatoeba] [https://tatoeba.org/eng/user/profile/GlossaMatik GlossaMatik] [https://tatoeba.org/eng/user/profile/eastasiastudent eastasiastudent])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |这种科技的优势是什么?}} || zhe4/zhei4 chong2/zhong3/zhong4 ke1 ji4 de5 you1 shi4 shi4 shi2 me5 ?|| Was ist der Vorteil dieser Technologie? (Mandarin, [https://tatoeba.org/eng/sentences/show/389806 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/MUIRIEL MUIRIEL])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |显然地势必要做些什麼。}} || xian3 ran2 de4/di4 shi4 bi4 yao4 zuo4 xie1 shi2 me5 。|| Es ist klar, was getan werden muss. (Mandarin, [https://tatoeba.org/eng/sentences/show/797039 Tatoeba] [https://tatoeba.org/eng/user/profile/Martha Martha] [https://tatoeba.org/eng/user/profile/xtofu80 xtofu80])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |汤姆对局势一无所知。}} || tang1 mu3 dui4 ju2 shi4 yi1 wu2 suo3 zhi1 。|| Tom knows nothing about the situation. (Mandarin, [https://tatoeba.org/eng/sentences/show/7885811 Tatoeba] [https://tatoeba.org/eng/user/profile/basilhan basilhan] [https://tatoeba.org/eng/user/profile/CK CK])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |那是个微妙的局势。}} || na4/nei4 shi4 ge4 wei2 miao4 de5 ju2 shi4 。|| Das ist eine prekäre Situation. (Mandarin, [https://tatoeba.org/eng/sentences/show/9637787 Tatoeba] [https://tatoeba.org/eng/user/profile/iiujik iiujik] [https://tatoeba.org/eng/user/profile/Pfirsichbaeumchen Pfirsichbaeumchen])
|}
=== 攫 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|}
=== 鸷 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|}
=== 猛 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |别像猪一样猛吃东西。}} || bie2 xiang4 zhu1 yi1 yang4 meng3 chi1 dong1 xi1 。|| Friss nicht wie ein Schwein! (Mandarin, [https://tatoeba.org/eng/sentences/show/1790135 Tatoeba] [https://tatoeba.org/eng/user/profile/sadhen sadhen] [https://tatoeba.org/eng/user/profile/Manfredo Manfredo])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |人要從狗猛酒酸的典故中吸取教訓。}} || ren2 yao4 cong2 gou3 meng3 jiu3 suan1 de5 dian3 gu4 zhong1/zhong4 xi1 qu3 jiao1 xun4 。|| Man must take a lesson from difficult situation and bad condition which befall in her/his life. (Mandarin, [https://tatoeba.org/eng/sentences/show/1502720 Tatoeba] [https://tatoeba.org/eng/user/profile/holger_reinherzen holger_reinherzen])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |人要从狗猛酒酸的典故中吸取教训。}} || ren2 yao4 cong2 gou3 meng3 jiu3 suan1 de5 dian3 gu4 zhong1/zhong4 xi1 qu3 jiao1 xun4 。|| Man must take a lesson from difficult situation and bad condition which befall in her/his life. (Mandarin, [https://tatoeba.org/eng/sentences/show/1502720 Tatoeba] [https://tatoeba.org/eng/user/profile/holger_reinherzen holger_reinherzen])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |风愈吹愈猛。}} || feng1 yu4 chui1 yu4 meng3 。|| The wind is picking up. (Mandarin, [https://tatoeba.org/eng/sentences/show/362626 Tatoeba] [https://tatoeba.org/eng/user/profile/nickyeow nickyeow] [https://tatoeba.org/eng/user/profile/CK CK])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |男人的思维方式和女人不同,所以有些男人的表达方式比较生猛。}} || nan2 ren2 de5 si1 wei2 fang1 shi4 he2/he4/huo2 nü3/ru3 ren2 bu4 tong2 , suo3 yi3 you3 xie1 nan2 ren2 de5 biao3 da2 fang1 shi4 bi4 jiao4 sheng1 meng3 。|| Männer denken anders als Frauen, deswegen drücken sich manche Männer etwas forsch aus. (Mandarin, [https://tatoeba.org/eng/sentences/show/2704948 Tatoeba] [https://tatoeba.org/eng/user/profile/fenfang557 fenfang557] [https://tatoeba.org/eng/user/profile/Yorwba Yorwba])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |老虎是一种非常凶猛的动物。}} || lao3 hu1/hu3 shi4 yi1 chong2/zhong3/zhong4 fei1 chang2 xiong1 meng3 de5 dong4 wu4 。|| A tiger is a very ferocious kind of animal. (Mandarin, [https://tatoeba.org/eng/sentences/show/789713 Tatoeba] [https://tatoeba.org/eng/user/profile/vgigregg vgigregg])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |旅行社的利润猛涨。}} || lü3 hang2/xing2 she4 de5 li4 run4 meng3 zhang3 。|| Die Gewinne der Reisegesellschaften stiegen gewaltig. (Mandarin, [https://tatoeba.org/eng/sentences/show/334732 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/xtofu80 xtofu80])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |风刮得太猛,他们没法在公园里玩了。}} || feng1 gua1 de2/de5/dei3 tai4 meng3 , ta1 men5 mei2/mo4 fa3 zai4 gong1 yuan2 li3 wan2/wan4 le5 。|| Der Wind blies zu stark, um im Park zu spielen. (Mandarin, [https://tatoeba.org/eng/sentences/show/333203 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/Yorwba Yorwba])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |看到警察走来,他猛地跑了开去。}} || kan4 dao4 jing3 察 zou3 lai2 , ta1 meng3 de4/di4 pao3 le5 kai1 qu4 。|| When he saw a policeman coming, he began to run like anything. (Mandarin, [https://tatoeba.org/eng/sentences/show/1950512 Tatoeba] [https://tatoeba.org/eng/user/profile/fercheung fercheung])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |風愈吹愈猛。}} || feng1 yu4 chui1 yu4 meng3 。|| The wind is picking up. (Mandarin, [https://tatoeba.org/eng/sentences/show/362626 Tatoeba] [https://tatoeba.org/eng/user/profile/nickyeow nickyeow] [https://tatoeba.org/eng/user/profile/CK CK])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |风吹得很猛。}} || feng1 chui1 de2/de5/dei3 hen3 meng3 。|| It is blowing very hard. (Mandarin, [https://tatoeba.org/eng/sentences/show/791670 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong])
|}
=== 赦 ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦之。}} || she4 zhi1 。|| Sie hat ihm vergeben. Verzeih ihr! (klassisch, [https://tatoeba.org/eng/sentences/show/1319057 Tatoeba] [https://tatoeba.org/eng/user/profile/shanghainese shanghainese] [https://tatoeba.org/eng/user/profile/Esperantostern Esperantostern] [https://tatoeba.org/eng/user/profile/Yorwba Yorwba])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦之。}} || she4 zhi1 。|| Sie hat ihm vergeben. (klassisch, [https://tatoeba.org/eng/sentences/show/1319057 Tatoeba] [https://tatoeba.org/eng/user/profile/shanghainese shanghainese] [https://tatoeba.org/eng/user/profile/Esperantostern Esperantostern])
|}
=== einzusortieren ===
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势如破竹}} || shì rú pò zhú || Kraft, wie brechender Bambus ([[wikt:en:势如破竹 |Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |鼎足之势}} || dǐng zú zhī shì ||Ein Dreibein von Kräften ([[wikt:en:鼎足之势 |Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势不可当}} || shì bù kě dāng || kräftig und nicht zu stoppen ([[wikt:en:势不可当 |Wiktionary en]]) (HSK 3.0 Band 7-9)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |时势造英雄}} || shí shì zào yīng xióng || Zeit erzeugt einen Helden ([[wikt:en:时势造英雄 |Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |猛虎}} || měng hǔ || ein wilder Tiger; ein tapferer Kämpfer ([[wikt:en:猛虎 |Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |贼势危急 }} || zei2 shi4 wei1 ji2 ||The bandit rebels' situation was desperate. ([[s:en:Special:PermanentLink/5495657 | Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第002回 | 三國演義/第002回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |在位期间(—前2254年),国势强盛}} || zai4 wei4 ji1/qi1 jian1 (— qian2 2254 nian2 ), guo2 shi4 jiang4/qiang2/qiang3 sheng4 || Während seiner Thronzeit (bis 2254 v. Chr.) ist die Landesstärke groß und in Blüte. ([[Vokabeltexte_Chinesisch/_Geschichtsdetails/_23._Jahrhundert_v._Chr. |Geschichtsdetails]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |正是:人情势利古犹今}} || zheng4 shi4 : ren2 qing2 shi4 li4 gu3 you2 jin1 || It was a case of: Human emotions are powerful, from ancient times until now ([[s:en:Special:PermanentLink/5776532 |Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第001回 | 三國演義/第001回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |贼势大败 }} || zei2 shi4 da4 bai4 ||The power of the bandit rebels was now greatly diminished ([[s:en:Special:PermanentLink/5776532 |Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第001回 | 三國演義/第001回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |话说天下大势,分久必合,合久必分。}} || hua4 shuo1 tian1 xia4 da4 shi4 , fen1 jiu3 bi4 he2 , he2 jiu3 bi4 fen1 。||It is a general truism of this world that anything long divided will surely unite, and anything long united will surely divide. ([[s:en:Special:PermanentLink/5776532 |Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第001回 | 三國演義/第001回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势服人、心不然}} || shi4 fu2 ren2 、 xin1 bu4 ran2 || Unterdrückst Du mit Gewalt die Leute, ist deren Herz nicht unterworfen ([[Vokabeltexte_Chinesisch/_Vokabellektionen/_Lektion_637|Di Zi Gui Schülerregeln]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |A见B势大 }} || A jian4/xian4 B shi4 da4 ||A saw that B's army was powerful ([[s:en:Special:PermanentLink/5495657 | Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第002回 | 三國演義/第002回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |今日可乘势尽诛之}} || jin1 ri4 ke3/ke4 cheng2/sheng4 shi4 jin4 zhu1 zhi1 || now we should seize the opportunity to kill them all ([[s:en:Special:PermanentLink/5495657 | Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第002回 | 三國演義/第002回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |张举见势败 }} || zhang1 ju3 jian4/xian4 shi4 bai4 ||Zhang Ju saw that the situation was hopeless ([[s:en:Special:PermanentLink/5495657 | Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第002回 | 三國演義/第002回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |卓自是威势越大}} || zhuo2 zi4 shi4 wei1 shi4 yue4 da4 ||Zhuo's prestige grew even stronger after this ([[s:en:Special:PermanentLink/5495659 |Wikisource: Romance of the Three Kingdoms]] [[s:zh:三國演義/第003回 | 三國演義/第003回]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |在好些医生手里受了许多的苦,又花尽了他所有的,一点也不见好,病势反倒更重了。 }} || zai4 hao3 xie1 yi1 sheng1 shou3 li3 shou4 le5 xu3 duo1 de5 ku3 , you4 hua1 jin4 le5 ta1 suo3 you3 de5 , yi1 dian3 ye3 bu4 jian4/xian4 hao3 , bing4 shi4 fan3 dao3 geng4 chong2/zhong4 le5 。 ||5.26 und vieles erlitten hatte von vielen Ärzten und alle ihre Habe verwandt und keinen Nutzen davon gehabt hatte (es war vielmehr schlimmer mit ihr geworden), kam, ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Markusevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |9.5或说:你的罪赦了,或说:你起来行走,那一样容易呢?}} || 9.5 huo4 shuo1 : ni3 de5 zui4 she4 le5 , huo4 shuo1 : ni3 qi3 lai2 hang2/xing2 zou3 , na4/nei4 yi1 yang4 rong2 yi4 ne5 ?|| 9.5 Denn was ist leichter, zu sagen: Deine Sünden sind vergeben, oder zu sagen: Stehe auf und wandle? ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Matthäusevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |叫他的百姓因罪得赦,就知道救恩。 }} || jiao4 ta1 de5 bai3 xing4 yin1 zui4 de2/de5/dei3 she4 , jiu4 zhi1 dao4 jiu4 en1 。 ||1.77 um seinem Volke Erkenntnis des Heils zu geben in Vergebung ihrer Sünden, ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Lukasevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |所以我告诉你,他许多的罪都赦免了,因为他的爱多;但那赦免少的,他的爱就少。 }} || suo3 yi3 wo3 gao4 su4 ni3 , ta1 xu3 duo1 de5 zui4 dou1/du1 she4 mian3 le5 , yin1 wei2/wei4 ta1 de5 ai4 duo1 ; dan4 na4/nei4 she4 mian3 shao3 de5 , ta1 de5 ai4 jiu4 shao3 。 ||7.47 Deswegen sage ich dir: Ihre vielen Sünden sind vergeben, denn sie hat viel geliebt; wem aber wenig vergeben wird, der liebt wenig. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Lukasevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |於是对那女人说:你的罪赦免了。 }} || yu2 shi4 dui4 na4/nei4 nü3/ru3 ren2 shuo1 : ni3 de5 zui4 she4 mian3 le5 。 ||7.48 Er aber sprach zu ihr: Deine Sünden sind vergeben. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Lukasevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |你们赦免谁的罪,谁的罪就赦免了;你们留下谁的罪,谁的罪就留下了。 }} || ni3 men5 she4 mian3 shei2 de5 zui4 , shei2 de5 zui4 jiu4 she4 mian3 le5 ; ni3 men5 liu2 xia4 shei2 de5 zui4 , shei2 de5 zui4 jiu4 liu2 xia4 le5 。 ||20.23 Welchen irgend ihr die Sünden vergebet, denen sind sie vergeben, welchen irgend ihr sie behaltet, sind sie behalten. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Johannesevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |或说你的罪赦了,或说你起来行走,那一样容易呢? }} || huo4 shuo1 ni3 de5 zui4 she4 le5 , huo4 shuo1 ni3 qi3 lai2 hang2/xing2 zou3 , na4/nei4 yi1 yang4 rong2 yi4 ne5 ? ||5.23 Was ist leichter, zu sagen: Dir sind deine Sünden vergeben, oder zu sagen: Stehe auf und wandle? ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Lukasevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |他就来到约但河一带地方,宣讲悔改的洗礼,使罪得赦。 }} || ta1 jiu4 lai2 dao4 yue1 dan4 he2 yi1 dai4 de4/di4 fang1 , xuan1 jiang3/jiang5 hui3 gai3 de5 xi3/xian3 li3 , shi3/shi4 zui4 de2/de5/dei3 she4 。 ||3.3 Und er kam in die ganze Umgegend des Jordan und predigte die Taufe der Buße zur Vergebung der Sünden; ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Lukasevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |照这话,约翰来了,在旷野施洗,传悔改的洗礼,使罪得赦。 }} || zhao4 zhe4/zhei4 hua4 , yue1 han4 lai2 le5 , zai4 kuang4 野 shi1 xi3/xian3 , chuan2/zhuan4 hui3 gai3 de5 xi3/xian3 li3 , shi3/shi4 zui4 de2/de5/dei3 she4 。 ||1.4 Johannes kam und taufte in der Wüste und predigte die Taufe der Buße zur Vergebung der Sünden. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Markusevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |26.28因为这是我立约的血,为多人流出来,使罪得赦。}} || 26.28 yin1 wei2/wei4 zhe4/zhei4 shi4 wo3 li4 yue1 de5 xie3/xue4 , wei2/wei4 duo1 ren2 liu2 chu1 lai2 , shi3/shi4 zui4 de2/de5/dei3 she4 。|| 26.28 Denn dieses ist mein Blut, das des neuen Bundes, welches für viele vergossen wird zur Vergebung der Sünden. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Matthäusevangelium]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |大势已去}} || da4 shi4 yi3 qu4 ||([[wikt:en:大势已去|Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |这种科技的优势是什么?}} || zhe4/zhei4 chong2/zhong3/zhong4 ke1 ji4 de5 you1 shi4 shi4 shi2 me5 ?||Was ist der Vorteil dieser Technologie? [https://tatoeba.org/eng/sentences/show/389806 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/MUIRIEL MUIRIEL]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她的父母不能不担心她的伤势。}} || ta1 de5 fu4 mu3 bu4 neng2 bu4 担 xin1 ta1 de5 shang1 shi4 。||Her parents can't help worrying about her injuries. [https://tatoeba.org/eng/sentences/show/2394593 Tatoeba] [https://tatoeba.org/eng/user/profile/fenfang557 fenfang557] [https://tatoeba.org/eng/user/profile/CK CK]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她给我打了一个看不懂的手势。}} || ta1 gei3 wo3 da3 le5 yi1 ge4 kan4 bu4 dong3 de5 shou3 shi4 。||She gave me a hand gesture I didn't understand. [https://tatoeba.org/eng/sentences/show/4764877 Tatoeba] [https://tatoeba.org/eng/user/profile/ryanwoo ryanwoo] [https://tatoeba.org/eng/user/profile/garborg garborg]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势不可当}} || shi4 bu4 ke3/ke4 dang1/dang4 ||([[wikt:en:势不可当|Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |她充分利用她住在伦敦的优势,提高英语。}} || ta1 chong1 fen1 li4 yong4 ta1 zhu4 zai4 lun2 dun1 de5 you1 shi4 , ti2 gao1 ying1 yu3 。||Sie nutzte ihren Londonaufenthalt voll aus, um ihr Englisch zu verbessern. [https://tatoeba.org/eng/sentences/show/863949 Tatoeba] [https://tatoeba.org/eng/user/profile/kooler kooler] [https://tatoeba.org/eng/user/profile/Pfirsichbaeumchen Pfirsichbaeumchen]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势如破竹}} || shi4 ru2 po4 zhu2 ||([[wikt:en:势如破竹|Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |鼎足之势}} || ding3 zu3 zhi1 shi4 ||([[wikt:en:鼎足之势|Wiktionary en]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |老虎是一种非常凶猛的动物。}} || lao3 hu1/hu3 shi4 yi1 chong2/zhong3/zhong4 fei1 chang2 xiong1 meng3 de5 dong4 wu4 。||A tiger is a very ferocious kind of animal. [https://tatoeba.org/eng/sentences/show/789713 Tatoeba] [https://tatoeba.org/eng/user/profile/vgigregg vgigregg]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |虽猛虎也,而今已死矣。}} || sui1 meng3 hu1/hu3 ye3 , er2 jin1 yi3 si3 yi3 。||War er auch ein grimmiger Tiger, so ist er doch heute schon tot. ([http://ctext.org/lv-shi-chun-qiu/zhs Lü Bu We] [http://www.zeno.org/pnd/119012251 Richard Wilhelm])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |看到警察走来,他猛地跑了开去。}} || kan4 dao4 jing3 察 zou3 lai2 , ta1 meng3 de4/di4 pao3 le5 kai1 qu4 。||When he saw a policeman coming, he began to run like anything. [https://tatoeba.org/eng/sentences/show/1950512 Tatoeba] [https://tatoeba.org/eng/user/profile/fercheung fercheung]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |旅行社的利润猛涨。}} || lü3 hang2/xing2 she4 de5 li4 run4 meng3 zhang3 。||Der Profit der Reiseagentur stieg stark an. [https://tatoeba.org/eng/sentences/show/334732 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/pinky pinky]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |风刮得太猛,他们没法在公园里玩了。}} || feng1 gua1 de2/de5/dei3 tai4 meng3 , ta1 men5 mei2/mo4 fa3 zai4 gong1 yuan2 li3 wan2/wan4 le5 。||The wind blew too hard for them to play in the park. [https://tatoeba.org/eng/sentences/show/333203 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong] [https://tatoeba.org/eng/user/profile/CM CM]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |别像猪一样猛吃东西。}} || bie2 xiang4 zhu1 yi1 yang4 meng3 chi1 dong1 xi1 。||Friss nicht wie ein Schwein! [https://tatoeba.org/eng/sentences/show/1790135 Tatoeba] [https://tatoeba.org/eng/user/profile/sadhen sadhen] [https://tatoeba.org/eng/user/profile/Manfredo Manfredo]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |风吹得很猛。}} || feng1 chui1 de2/de5/dei3 hen3 meng3 。||It is blowing very hard. [https://tatoeba.org/eng/sentences/show/791670 Tatoeba] [https://tatoeba.org/eng/user/profile/fucongcong fucongcong]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |赦之。}} || she4 zhi1 。||Sie hat ihm vergeben. [https://tatoeba.org/eng/sentences/show/1319057 Tatoeba] [https://tatoeba.org/eng/user/profile/shanghainese shanghainese] [https://tatoeba.org/eng/user/profile/Esperantostern Esperantostern]
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |其有若此者,行罪无赦}} || qi2 you3 ruo4 ci3 zhe3 , hang2/xing2 zui4 wu2 she4 ||Wer sich etwa derartiges zuschulden kommen läßt, wird unnachsichtlich bestraft. ([http://ctext.org/lv-shi-chun-qiu/zhs Lü Bu We] [http://www.zeno.org/pnd/119012251 Richard Wilhelm])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |其有若此者,行罪無赦}} || qi2 you3 ruo4 ci3 zhe3 , hang2/xing2 zui4 wu2 she4 ||Wer sich etwa derartiges zuschulden kommen läßt, wird unnachsichtlich bestraft. ([http://ctext.org/lv-shi-chun-qiu/zhs Lü Bu We] [http://www.zeno.org/pnd/119012251 Richard Wilhelm])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |众先知也为他作见证说:凡信他的人必因他的名得蒙赦罪。}} || zhong4 xian1 zhi1 ye3 wei2/wei4 ta1 zuo4 jian4/xian4 zheng4 shuo1 : fan2 xin4 ta1 de5 ren2 bi4 yin1 ta1 de5 ming2 de2/de5/dei3 meng2 she4 zui4 。||43 Diesem geben alle Propheten Zeugnis, daß jeder, der an ihn glaubt, Vergebung der Sünden empfängt durch seinen Namen. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Apostelgeschichte]])
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |我差你到他们那里去,要叫他们的眼睛得开,从黑暗中归向光明,从撒但权下归向神;又因信我,得蒙赦罪,和一切成圣的人同得基业。}} || wo3 cha4/chai1 ni3 dao4 ta1 men5 na4/nei4 li3 qu4 , yao4 jiao4 ta1 men5 de5 yan3 jing1 de2/de5/dei3 kai1 , cong2 hei1 an4 zhong1/zhong4 gui1 xiang4 guang1 ming2 , cong2 sa1/sa3 dan4 quan2 xia4 gui1 xiang4 shen2 ; you4 yin1 xin4 wo3 , de2/de5/dei3 meng2 she4 zui4 , he2/he4/huo2 yi1 qie1 cheng2 sheng4 de5 ren2 tong2 de2/de5/dei3 ji1 ye4 。||18 ihre Augen aufzutun, auf daß sie sich bekehren von der Finsternis zum Licht und von der Gewalt des Satans zu Gott, auf daß sie Vergebung der Sünden empfangen und ein Erbe unter denen, die durch den Glauben an mich geheiligt sind. ([[Diskussion:Vokabeltexte_Chinesisch/_Vokabellektionen#Das_Neue_Testament|Die Bibel - Apostelgeschichte]])
|}
== Lückentexte ==
=== 小杨式太极拳 / 杨式十式太极拳 Taijiquan: kleine Yang-Form/ 10er Yang-Form===
{| class="wikitable"
|-
| 1 || 起势 || qǐ shì || Vorbereitung, das Qi wecken
|-
| 2 || 左右 倒 卷 Oberarm || zuǒ yòu dào juǎn gōng || den Affen abwehren, links und rechts
|-
| 3 || 左右 greife Knie, knicke 步 || zuǒ yòu lǒu xī ǎo bù || das Knie streifen, links und rechts
|-
| 4 || 左右野马分 Pferdemähne || zuǒ yòu yě mǎ fēn zōng || die Mähne des Wildpferds teilen, links und rechts
|-
| 5 || 左右云手 || zuǒ yòu yún shǒu || Wolkenhände, links und rechts
|-
| 6 || 左右金鸡独立 || zuǒ yòu jīn jī dú lì || der goldene Hahn steht auf einem Bein, links und rechts
|-
| 7 || 左右 treten 脚 || zuǒ yòu dēng jiǎo || Fersentritt, rechts und links
|-
| 8 || 左右揽 Spatzen 尾<br/>Abwehr<br/>zurückweichen<br/>drücken<br/>按 || yòu zuǒ lǎn què wěi <br/> yòu zuǒ bīng<br/>lǚ<br/>jǐ<br/>àn|| Den Spatz am Schwanz fassen, links und rechts<br/> Abwehr<br/> zurückweichen<br/> drücken<br/> stoßen
|-
| 9 || 十字手 || shí zì shǒu || Hände kreuzen
|-
| 10 || 收势 || shōu shì || Abschluß
|}
=== [http://magazine.marcopoloproject.org/%E5%90%8C%E5%BA%8A%E5%A5%BD%E5%8F%8B-%EF%BC%8Dfriends-benefits/ the marco polo project: 同床好友] ===
一位 anonym 的网友来信说:
明天要考英语了,一个学期没上课,本来应该临时抱佛脚的,但复习不进去,挂就挂吧。这段时间发生的事情太乱了。我也不想要有什么解决方式,甚至也不想有太多人看见,我只想说说。周围的朋友都不能够说,不够亲近,或是不能理解。
现在 MoMo 这类的应用挺多。那天晚上睡不着就用手机上了下QQ,又神使鬼差地去查找了 in der Nähe 的人。过不多久有个人打招呼,“兼职”。当时我不知道半夜这个时段净是单身 und einsam 男求 "Freundschaft plus" 的,要是知道 vermutlich 就忽略掉了。觉得很奇怪,就问兼什么职。那边就答,学生兼职。一次八十包夜两百。我 in diesem Moment 就明白了。但是出于好玩,就顺着话头回了他,说价太低,你再加点,还要戴套。就这么一来二往 ging so 好久,我直觉他人其实挺靠谱的,不像要找小姐的人。后来他说他是因为心情不好,想找人出来说说话。问能不能第二天一起吃一个晚饭,就 mit 他说说话。他说是按时计费,会给钱的。我想想也就答应了。然后此时一阵 äußerst的困意袭来,当时四点多,我就去睡了。
第二天下午三点多的时候,他说他女朋友来找他,走不开,问能不能晚点再去,然后就不要回了(他知道我是学生,晚上有门禁太晚了不能回),说不会做,就说说话。照常理我是不该去的,但结果我还是等到了八点钟出门了。到了约定的接头地点,等了一阵他过来了。说真的本来我以为他该工作几年了,所以第一眼看去觉得,嗯,真是工作几年了吧。结果后来才 fand heraus 居然比我还小一年,也还在上学 -_!! 表示外貌好成熟。然后就去吃了点东西。渐渐我就知道了,他是因为女朋友 eine Affäre hatte 特别伤心,又不知道怎么办,很 verwirrt,所以朋友建议他这样找一个来 “ablenkende 情绪”。然后就去开房了(Hey,为什么去开房?废话,要不然晚上怎么过一夜?)我去洗澡的时候他 währenddessen 买了一堆酒回来,这架势真要喝一晚上。然后就开喝,开始 reden 各种。其实聊得挺投机的。Dabei 有很多小细节很感动我,是个很 rücksichtsvoll 很细心的人。但是因为 immer wieder 涉及他的感情问题,酒喝得痛苦,话也讲得痛苦。可以看出他真的很爱很爱那个女孩子。然后就这么 fortfahren 到了四五点,都困得不行了,legten uns 一张床上睡了。是的,木有发生关系。
第二天起得早,因为我有考试要急着 heimgehen。但其实一天都过得 konfus 的,完全不能相信我前晚居然跟一个才认识不超过一天的 unbekannter 男人 liegen 在一张床上过了一晚。我也是有男朋友的,关系也很 stabil。但不知道为什么事情居然就那么荒诞地发生了。一直 konnte mir keinen Reim daraus machen。可能就是因为这种又奇怪又荒诞的感觉,我居然发现对他的感觉很不一般。就是,像喜欢上一个人的感觉。想了解他的所有,他发信息过来会很高兴。就这么短短几天,我发现我自己的感情发展得有点 zu schnell。在感情方面我一般比较理智,这一次真的不知道自己在想什么。昨天他又叫我出去。同样的理由同样的地方,连房间都是一样的。如果说第一次是因为好玩,aufregend,那这次呢?我不敢想我为什么还要答应。这次他仍然是一堆酒一堆烟,因为跟女朋友又吵架了。半夜的时候他出去买宵夜,电脑开着QQ挂着,我 konnte nicht widerstehen 还是 durchstöbern 他和他女朋友的聊天记录。不是不难过的。他们那么好,我这算什么事儿呢。然后 mit 他看了场球,西班牙对法国。他说他跟人堵法国会 gewinnen,要是 verlor 的话我得借他一肾去卖,要不然 leisten zu verlieren。我说出门时把肾忘 Schlafzimmer 了。他就说,那就 Lunge 吧,这总该带了。我多想讲,就算我 vollkommen verfallen 出来了,又怎么样呢,你要么。
下半场的时候我们俩都 lagen im Bett。都知道这场球法国要 verlieren。他喝酒喝得多,说不了几句话就睡了。睡得很不 fest,不停踢被子。我就不停帮他盖上。一边盖觉得好心酸。这算怎么个事儿呢。他有女朋友,我也有男朋友,但是怎么就能在一张床上一起睡了俩晚上呢,尽管没发生关系。最荒唐的是我怎么会喜欢他,才认识五天不到。
乱得很,先这样。
[http://magazine.marcopoloproject.org/authors/Shu%20Dong%20-%20%E6%A0%91%E6%B4%9E/ Shu Dong]
[http://magazine.marcopoloproject.org/%e5%90%8c%e5%ba%8a%e5%a5%bd%e5%8f%8b-%ef%bc%8d-friends-with-benefits-english/ Übersetzung]
Friends with benefits
An anonymous online friend of mine sent this to me:
I have my English exam tomorrow. Since I didn’t attend class for a whole semester, I should be cramming right now. But I cannot continue studying, who cares if I flunk it? What happened recently is too messed up. I don’t want a solution, and I don’t want too many people to see this. I just want to talk about it. I can’t tell my friends because they are not close enough or won’t understand where I’m coming from.
There are many uses of MoMo these days. I couldn’t sleep the other night so I went on QQ (a popular instant messaging program in China) on my mobile phone. For some reason I decided to search for people who are nearby. It didn’t take long for someone to PM me, “part time”. At that time, I didn’t know that it was that time of the night when single and lonely men search for friends with benefits. If I did know, it probably slipped my mind at that time. I felt curious, so I asked him, “What do you do mean ‘part time’?” On the other end, he replied, “Part time student. Eighty for a one off and two hundred for the night”. In that instance, I understood. But I decided to play along and replied “The price is too low. Raise it and include a ‘packaged deal’.” This exchange went on for a while, and I started to feel that this guy wasn’t as dodgy as I initially thought. He didn’t look as if he was looking for a booty call. Later, he said that he was feeling pretty lousy and wanted to find someone for a chat. He asked if we could meet up for dinner and a chat the next day. He said that he will pay by the hour. I thought about it and agreed. Afterwards, I suddenly felt really tired as it was already four in the morning so I went to asleep.
At around three in the afternoon the next day, he said that his girlfriend was over and he couldn’t get away. He asked if we can meet later and spend the night (he knows that I’m a student and there’s a curfew. There’s no way I can head home if I’m out too late.) No sex, just chatting. Common sense told me that I shouldn’t go, but still I waited until eight in the evening before heading out. I got to the meeting point and he came a while later. Honestly, I thought that he had probably been working for a few years so when I first saw him, I thought, yeah, he’s been working for a while. Later, I found out that he was actually a year younger than me and still studying! This showed that he looks older. We went to get something to eat later. Slowly I understood, he’s upset because his girlfriend has gone off the rails and he has no idea what to do. He’s confused, and his friends suggested finding a ‘rebound’. Later, we went to a hotel room (Why? Please, how else do we spend the night?) When I was having a shower, he bought a ton of alcohol. Looks like we’ll be drinking all night. We started drinking and talking. It felt pretty good talking to him. Some of the little details were really touching and showed me that he’s a caring and considerate person. But because we kept talking about his relationship problems, it became more painful as we drank and talked. I could tell that he really really loved that girl. We kept this up till four or five in the morning, until we were so tired we collapsed into bed. That’s right, nothing else happened.
The next day I woke up early. Because of my exam, I had to rush back but I was out of it for the whole day. I couldn’t believe that the other night, I had slept in the same bed with a stranger whom I had known for less than a day. I’m also in a stable relationship with my boyfriend, but I have no idea how such a preposterous thing could have happened. I still couldn’t make sense of it. Maybe it’s because of this strange and ridiculous feeling, I felt that my feelings towards this guy are not normal, like, I kind of feel that I like him. I want to know everything about him, and when he sends me a message I feel really happy. In a space of a few days, I realised that my feelings have developed really quickly. With relationships I’m usually more rational, but this time I have no idea what I’m thinking about. Yesterday he asked me out again. Same reason, same place; even the hotel room was the same. If the first time was fun and exciting, what about this time? I didn’t dare to think about why I have to answer that. This time, he brought a ton of alcohol and cigarettes. He had fought with his girlfriend again. In the middle of the night, he went out to get supper. His QQ was open on the computer, so I had a look through his chat logs with his girlfriend. I would be lying if I said that I wasn’t disappointed. They were great together, what am I compared to that? Later we watched a soccer match together, Spain verses France. He said, he had a bet with someone that France would win. If he lost, I would have sell one of his kidneys or else he wouldn’t know how to pay up. I told him that I forgot my kidney in my room. He said, “how about your lungs, surely you’ve brought them”. I really wanted to say, “So what if I take out my heart and my lungs? Do you want them?”
During the second half, we lied down in bed. We both knew that France was going to lose this match. He had drunk too much and fell asleep without saying too much. He didn’t sleep too well and kept kicking at the blanket. I kept covering him up again. Every time I did that, I felt horrible inside. What the hell is this? He has a girlfriend, I have a boyfriend, but why have we slept together in the same bed for two nights? Even though nothing happened, the most ridiculous thing is that I’ve started falling for him, and we’ve only known each other for less than five days.
This is messed up, but it’ll do for now.
[http://magazine.marcopoloproject.org/author/julienleyre/ Julien Leyre] [http://julienleyre.wordpress.com website]
=== Bibel ===
==== [https://newchristianbiblestudy.org/de/bible/compare/chinese-union-s/german-elberfelder-1905/ephesians/1/ Epheserbrief Kapitel 1] ====
{| class="wikitable"
! Chinese Union Version !! Übersetzung Rudolf Brockhaus (1856-1932)
|-
| 奉神旨意,作 Christi Jesu 使徒的保罗,写信给在 Ephesus 的圣徒,就是在 Christi Jesu 里有忠心的人。|| Paulus, Apostel Jesu Christi durch Gottes willen, den Heiligen und Treuen in Christo Jesu, die in Ephesus sind:
|-
| 愿 Gnade、平安从神我们的父和主 Jesus Christus 归与你们!|| Gnade euch und Friede von Gott, unserem Vater, und dem Herrn Jesus Christus!
|-
| 愿 Preis 归与我们主 Jesus Christus 的父神!他在 Christo 里曾 gesegnet 我们天上各样属灵的福气:|| Gepriesen sei der Gott und Vater unseres Herrn Jesus Christus, der uns gesegnet hat mit jeder geistlichen Segnung in den himmlischen Örtern in Christo,
|-
| 就如神从创立世界以前,在 Christo 里 auserwählt-了 我们,使我们在他面前成为圣洁,无有瑕疵;|| wie er uns auserwählt hat in ihm vor Grundlegung der Welt, daß wir heilig und tadellos seien vor ihm in Liebe;
|-
| 又因爱我们,就按着自己意旨所 Wohlgefallen 的,预定我们 durch Jesum Christum 得儿子的名分,|| und uns zuvorbestimmt hat zur Sohnschaft durch Jesum Christum für sich selbst nach dem Wohlgefallen seines Willens,
|-
| 使他荣耀的恩典得着 Lobpreis;这恩典是他在爱子里所 begnadigt 我们的。|| zum Preise der Herrlichkeit seiner Gnade, worin er uns begnadigt hat in dem Geliebten,
|-
| 我们 durch 爱子的血得 Erlösung, Vergehungen 得以赦免,乃是照他丰富的恩典。|| in welchem wir die Erlösung haben durch sein Blut, die Vergebung der Vergehungen, nach dem Reichtum seiner Gnade,
|-
| 这恩典是神用诸般智慧聪明,充充足足赏给我们的;|| welche er gegen uns hat überströmen lassen in aller Weisheit und Einsicht,
|-
| 都是照他自己所预定的美意,叫我们知道他旨意的 Geheimnis,|| indem er uns kundgetan hat das Geheimnis seines Willens, nach seinem Wohlgefallen, das er sich vorgesetzt hat in sich selbst
|-
| 要照所安排的,在日期满足的时候,使天上、地上、一切所有的都在 Christus 里面同归於一。|| für die Verwaltung der Fülle der Zeiten: alles unter ein Haupt zusammenzubringen in dem Christus, das was in den Himmeln und das, was auf der Erde ist, in ihm,
|-
| 我们也在他里面得(或作:成)了基业;这原是那位随己意行、做万事的,照着他旨意所预定的,|| in welchem wir auch ein Erbteil erlangt haben, die wir zuvorbestimmt sind nach dem Vorsatz dessen, der alles wirkt nach dem Rate seines Willens,
|-
| 叫他的荣耀从我们这首先在 Christus 里有 gehofft 的人可以得着 Lobpreis。|| damit wir zum Preise seiner Herrlichkeit seien, die wir zuvor auf den Christus gehofft haben;
|-
| 你们既听见真理的道,就是那叫你们得救的福音,也信了 Christus,既然信他,就受了所应许的圣灵为印记。|| auf welchen auch ihr gehofft, nachdem ihr gehört habt das Wort der Wahrheit, das Evangelium eures Heils, in welchem ihr auch, nachdem ihr geglaubt habt, versiegelt worden seid mit dem Heiligen Geiste der Verheißung,
|-
| 这圣灵是我们得基业的 Beweis (原文作:质),直等到神之民(原文作:产业)被 Unterpfand,使他的荣耀得着 Lobpreis。|| welcher das Unterpfand unseres Erbes ist, zur Erlösung des erworbenen Besitzes, zum Preise seiner Herrlichkeit.
|-
| 因此,我既听见你们信从主 Jesus,亲爱众圣徒,|| Weshalb auch ich, nachdem ich gehört habe von dem Glauben an den Herrn Jesus, der in euch ist, und von der Liebe, die ihr zu allen Heiligen habt, nicht aufhöre,
|-
| 就为你们不住的感谢神。 Gebet 的时候,常题到你们,|| für euch zu danken, euer erwähnend in meinen Gebeten,
|-
| 求我们主 Jesus Christus 的神,荣耀的父,将那 gebe 人智慧和 Offenbarung 的灵赏给你们,使你们真知道他,|| auf daß der Gott unseres Herrn Jesus Christus, der Vater der Herrlichkeit, euch gebe den Geist der Weisheit und Offenbarung in der Erkenntnis seiner selbst, damit ihr,
|-
| 并且照明你们心中的眼睛,使你们知道他的恩召有何等指望,他在圣徒中得的基业有何等丰盛的荣耀;|| erleuchtet an den Augen eures Herzens, wisset, welches die Hoffnung seiner Berufung ist, und welches der Reichtum der Herrlichkeit seines Erbes in den Heiligen,
|-
| 并知道他向我们这信的人所显的能力是何等 überschwenglich,|| und welches die überschwengliche Größe seiner Kraft an uns, den Glaubenden, nach der Wirksamkeit der Macht seiner Stärke,
|-
| 就是照他在 Christus 身上所运行的大能大力,使他从死里复活,叫他在天上坐在自己的右边,|| in welcher er gewirkt hat in dem Christus, indem er ihn aus den Toten auferweckte (und er setzte ihn zu seiner Rechten in den himmlischen Örtern,
|-
| 远超过一切执政的、掌权的、有能的、主治的,和一切有名的;不但是今世的,连来世的也都超过了。|| über jedes Fürstentum und jede Gewalt und Kraft und Herrschaft und jeden Namen, der genannt wird, nicht allein in diesem Zeitalter, sondern auch in dem zukünftigen,
|-
| 又将万有服在他的脚下,使他为教会作万有之首。|| und hat alles seinen Füßen unterworfen und ihn als Haupt über alles der Versammlung gegeben,
|-
| 教会是他的身体,是那充满万有者所充满的。|| welche sein Leib ist, die Fülle dessen, der alles in allem erfüllt);
|}
==== [https://newchristianbiblestudy.org/de/bible/compare/chinese-union-s/german-elberfelder-1905/matthew/8/ Matthäusevangelium Kapitel 8] ====
{| class="wikitable"
! Chinese Union Version !! Übersetzung Rudolf Brockhaus (1856-1932)
|-
| 8.1 Jesus 下了山,有许多人跟着他。 || 8.1 Als er aber von dem Berge herabgestiegen war, folgten ihm große Volksmengen.
|-
| 8.2 有一个长大?Aussätziger 的来拜他,说:主若肯,必能叫我洁净了。 || 8.2 Und siehe, ein Aussätziger kam herzu und warf sich vor ihm nieder und sprach: Herr, wenn du willst, kannst du mich reinigen.
|-
| 8.3 Jesus streckte 手摸他,说:我肯,你洁净了罢!他的大?Aussatz 立刻就洁净了。 || 8.3 Und er streckte seine Hand aus, rührte ihn an und sprach: Ich will; sei gereinigt! Und alsbald wurde sein Aussatz gereinigt.
|-
| 8.4 Jesus 对他说:你切不可告诉人,只要去把身体给祭司察看,献上 Moses 所 angeordnet 的礼物,对众人作证据。 || 8.4 Und Jesus spricht zu ihm: Siehe, sage es niemand; sondern gehe hin, zeige dich dem Priester, und bringe die Gabe dar, die Moses angeordnet hat, ihnen zum Zeugnis.
|-
| 8.5 Jesus 进了Kapernaum,有一个百夫长进前来,求他说: || 8.5 Als er aber in Kapernaum eintrat, kam ein Hauptmann zu ihm, der ihn bat und sprach:
|-
| 8.6 主阿,我的 Knecht ist gelähmt, liegt 在家里,甚是疼苦。 || 8.6 Herr, mein Knecht liegt zu Hause gelähmt und wird schrecklich gequält.
|-
| 8.7 Jesus 说:我去医治他。 || 8.7 Und Jesus spricht zu ihm: Ich will kommen und ihn heilen.
|-
| 8.8 百夫长回答说:主阿,你到我舍下,我不敢当;只要你说一句话,我的 Knecht 就必好了。 || 8.8 Der Hauptmann aber antwortete und sprach: Herr, ich bin nicht würdig, daß du unter mein Dach tretest; sondern sprich nur ein Wort, und mein Knecht wird gesund werden.
|-
| 8.9 因为我在人的权下,也有兵在我以下;对这个说:去!他就去;对那个说:来!他就来;对我的 Knecht 说:你作这事!他就去作。 || 8.9 Denn auch ich bin ein Mensch unter Gewalt und habe Kriegsknechte unter mir; und ich sage zu diesem: Gehe hin, und er geht; und zu einem anderen: Komm, und er kommt; und zu meinem Knechte: Tue dieses, und er tut's.
|-
| 8.10 Jesus 听见就希奇,对跟从的人说:我实在告诉你们,这么大的信心,就是在以色列中,我也没有遇见过。 || 8.10 Als aber Jesus es hörte, verwunderte er sich und sprach zu denen, welche nachfolgten: Wahrlich, ich sage euch, selbst nicht in Israel habe ich so großen Glauben gefunden.
|-
| 8.11 我又告诉你们,从东从西,将有许多人来,在天国里与 Abraham、以撒、雅各一同坐席; || 8.11 Ich sage euch aber, daß viele von Osten und Westen kommen und mit Abraham und Isaak und Jakob zu Tische liegen werden in dem Reiche der Himmel,
|-
| 8.12 惟有本国的子民, sie 被 hinausgeworfen 外边黑暗里去,在那里必要哀哭切齿了。 || 8.12 aber die Söhne des Reiches werden hinausgeworfen werden in die äußere Finsternis: da wird sein das Weinen und das Zähneknirschen.
|-
| 8.13 Jesus 对百夫长说:你回去罢!照你的信心,给你成全了。那时,他的 Knecht 就好了。 || 8.13 Und Jesus sprach zu dem Hauptmann: Gehe hin, und dir geschehe, wie du geglaubt hast. Und sein Knecht wurde gesund in jener Stunde.
|-
| 8.14 Jesus 到了彼得家里,见彼得的 Schwiegermutter 害热病 daniederliegen 着。 || 8.14 Und als Jesus in das Haus des Petrus gekommen war, sah er dessen Schwiegermutter fieberkrank daniederliegen.
|-
| 8.15 Jesus 把他的手一摸,热就退了;他就起来服事 Jesus。 || 8.15 Und er rührte ihre Hand an, und das Fieber verließ sie; und sie stand auf und diente ihm.
|-
| 8.16 到了晚上,有人带着许多被鬼 besessen 的来到 Jesus 跟前,他只用一句话就把鬼都 austreiben,并且治好了一切有病的人。 || 8.16 Als es aber Abend geworden war, brachten sie viele Besessene zu ihm; und er trieb die Geister aus mit einem Worte, und er heilte alle Leidenden,
|-
| 8.17 这是要应验先知以赛亚的话,说:他代替我们的 Schwachheiten,担当我们的 Krankheiten。 || 8.17 damit erfüllt würde, was durch den Propheten Jesaias geredet ist, welcher spricht: "Er selbst nahm unsere Schwachheiten und trug unsere Krankheiten."
|-
| 8.18 Jesus 见许多人围着他,就 befahl er 渡到那边去。 || 8.18 Als aber Jesus eine große Volksmenge um sich sah, befahl er, an das jenseitige Ufer hinwegzufahren.
|-
| 8.19 有一个文士来,对他说:夫子,你无论往那里去,我要跟从你。 || 8.19 Und ein Schriftgelehrter kam herzu und sprach zu ihm: Lehrer, ich will dir nachfolgen, wohin irgend du gehst.
|-
| 8.20 Jesus 说:狐狸有洞,天空的飞鸟有窝,人子却没有枕头的地方。 || 8.20 Und Jesus spricht zu ihm: Die Füchse haben Höhlen, und die Vögel des Himmels Nester, aber der Sohn des Menschen hat nicht, wo er das Haupt hinlege.
|-
| 8.21 又有一个门徒对 Jesus 说:主阿,容我先回去 begraben 我的父亲。 || 8.21 Ein anderer aber von seinen Jüngern sprach zu ihm: Herr, erlaube mir, zuvor hinzugehen und meinen Vater zu begraben.
|-
| 8.22 Jesus 说: Laß 死人 begraben 他们的死人;你跟从我罢! || 8.22 Jesus aber sprach zu ihm: Folge mir nach, und laß die Toten ihre Toten begraben.
|-
| 8.23 Jesus 上了船,门徒跟着他。 || 8.23 Und als er in das Schiff gestiegen war, folgten ihm seine Jünger.
|-
| 8.24 海里忽然起了 ein großes Ungestüm,甚至船被波浪 bedeckt wurde; Jesus 却睡着了。 || 8.24 Und siehe, es erhob sich ein großes Ungestüm auf dem See, so daß das Schiff von den Wellen bedeckt wurde; er aber schlief.
|-
| 8.25 门徒来叫醒了他,说:主阿,救我们,我们丧命啦! || 8.25 Und die Jünger traten hinzu, weckten ihn auf und sprachen: Herr, rette uns, wir kommen um!
|-
| 8.26 Jesus 说:你们这小信的人哪,为什么 furchtsam 呢?於是起来,斥责风和海,风和海就大大的平静了。 || 8.26 Und er spricht zu ihnen: Was seid ihr furchtsam, Kleingläubige? Dann stand er auf und bedrohte die Winde und den See; und es ward eine große Stille.
|-
| 8.27 众人希奇,说:这是怎样的人?连风和海也听从他了! || 8.27 Die Menschen aber verwunderten sich und sprachen: Was für einer ist dieser, daß auch die Winde und der See ihm gehorchen?
|-
| 8.28 Jesus 既渡到那边去,来到加大拉人的地方,就有两个被鬼 besessen 的人从 Grüften 里出来迎着他,极其凶猛,甚至没有人能从那条路上经过。 || 8.28 Und als er an das jenseitige Ufer gekommen war, in das Land der Gergesener, begegneten ihm zwei Besessene, die aus den Grüften hervorkamen, sehr wütend, so daß niemand jenes Weges vorbeizugehen vermochte.
|-
| 8.29 他们 schrieen und 说:神的儿子,我们与你有什么相干?时候还没有到,你就上这里来叫我们受苦么? || 8.29 Und siehe, sie schrieen und sprachen: Was haben wir mit dir zu schaffen, Sohn Gottes? Bist du hierhergekommen, vor der Zeit uns zu quälen?
|-
| 8.30 离他们很远,有一大群猪吃食。 || 8.30 Es war aber fern von ihnen eine Herde vieler Schweine, welche weidete.
|-
| 8.31 鬼就央求 Jesus,说:若把我们 austreiben,就打发我们进入猪群罢! || 8.31 Die Dämonen aber baten ihn und sprachen: Wenn du uns austreibst, so sende uns in die Herde Schweine.
|-
| 8.32 Jesus 说:去罢!鬼就出来,进入猪群。全群忽然闯下 den Abhang,投在海里 kamen sie um。 || 8.32 Und er sprach zu ihnen: Gehet hin. Sie aber fuhren aus und fuhren in die Herde Schweine. Und siehe, die ganze Herde Schweine stürzte sich den Abhang hinab in den See, und sie kamen um in dem Gewässer.
|-
| 8.33 放猪的就 flohen und 进城,将这一切事和被鬼 besessen 的人所 erfahren 的都告诉人。 || 8.33 Die Hüter aber flohen und gingen in die Stadt und verkündeten alles und das von den Besessenen.
|-
| 8.34 合城的人都出来迎见 Jesu,既见了就央求他离开他们的境界。 || 8.34 Und siehe, die ganze Stadt ging hinaus, Jesu entgegen, und als sie ihn sahen, baten sie, daß er aus ihren Grenzen weggehen möchte. -
|}
=== Haenisch: Lehrgang der klassischen chinesischen Schriftsprache ===
==== 第七十七課 ====
第七十七课
dì qī shí qī kè
Siebenundsiebzigste Lektion
Eine Variante des Textes findet man auch im [[s:zh:%E9%9A%8B%E6%9B%B8/%E5%8D%B765| Buch der Sui-Dynastie]].
-----------------------------------
尚武
尚武
Shàng wǔ
Die Kriegskunst schätzen
-----------------------------------
Xue 世雄幼時與_ Gleichaltriger 游_
Xue 世雄幼时与群 Gleichaltriger 游戏
xuē shì xióng yòu shí yǔ qún bèi yóu xì
Xue Shiyong spielte in seiner Kindheit mit einer Gruppe Gleichaltriger
-----------------------------------
Variante
世雄為兒童時,與群 Gleichaltriger __
世雄为儿童时,与群 Gleichaltriger 游戏
Shì xióng wèi ér tóng shí, yǔ qún bèi yóu xì
Zur Zeit als Shiyong ein Kind war, spielte er mit einer Gruppe Gleichaltriger
-----------------------------------
畫地為城郭
画地为城郭
huà dì wèi chéng guō
Er zeichnete auf die Erde (eine Stadt mit) innerer und äußerer Stadtmauer.
-----------------------------------
令諸兒為 Angriffs 守之_
令诸儿为 Angriffs 守之势
lìng zhū er wéi gōng shǒu zhī shì
Er ließ alle anderen Kinder Angriffs- oder Verteidigungspositionen einnehmen.
-----------------------------------
無不用命
无不用命
Wú bù yòng mìng
Es gab keinen, der nicht seinen Befehlen gehorchte.
-----------------------------------
有不從令者
有不从令者
Yǒu bù cóng lìng zhě
Gab es einen, der nicht seinem Befehl folgte,
-----------------------------------
世雄 sofort schlagen 之
Shì xióng zhé tà zhī
so schlug Shiyong ihn sofort.
-----------------------------------
諸兒畏 und fürchteten ihn
诸儿畏 und fürchteten ihn
zhū er wèi dàn
Alle Kinder zitterten vor ihm und fürchteten ihn
-----------------------------------
皆甚齊整
皆甚齐整
jiē shén qí zhěng
Alles war sehr ordentlich angeordnet.
-----------------------------------
其父見之
其父见之
qí fù jiàn zhī
Sein Vater sah dies.
-----------------------------------
大喜
大喜
dà xǐ
Er freute sich sehr.
-----------------------------------
知其後必為名將
知其后必为名将
zhī qí hòu bì wèi míng jiàng
Er erkannte, dass dieser (Shixiong) später gewiss ein berühmter General werden würde.
-----------------------------------
Variante
其父見而奇之
其父见而奇之
Qí fù jiàn ér qí zhī
Sein Vater sah dies und war überrascht.
-----------------------------------
謂人曰
谓人曰
Wèi rén yuē
Er sagte zu den Menschen:
-----------------------------------
此兒當興吾家矣
此儿当兴吾家矣
Cǐ er dāng xìng wú jiā yǐ
Dieser Junge wird meine Familie erblühen lassen
-----------------------------------
後世雄果立_功
后世雄果立战功
hòu shì xióng guǒ lì zhàn gōng
Später vollbrachte Shixiong Kriegserfolge
-----------------------------------
====第一百零五課====
第一百零五课
dì yī bǎi líng wǔ kè
Hundertfünfte Lektion
Diese Lektion findet sich im [https://ctext.org/shuo-yuan/zhi-gong/zh Shuo Yuan] und in einer Variante im [[s:zh:%E5%B1%B1%E8%A5%BF%E9%80%9A%E5%BF%97_(%E5%9B%9B%E5%BA%AB%E5%85%A8%E6%9B%B8%E6%9C%AC)/%E5%8D%B7092|Shānxī tōng zhì]].
-----------------------------------
舅犯
舅犯
jiù fàn
Jiu Fan
-----------------------------------
_文公問於舅犯曰
晋文公问于舅犯曰
jìn wén gōng wèn yú jiù fàn yuē
Herzog Wen von Jin fragte Jiu Fan:
-----------------------------------
誰可使為西河守者
谁可使为西河守者
shéi kě shǐ wèi xī hé shǒu zhě
Wen kann ich als Stadthalter am Westfluss einsetzen
-----------------------------------
(舅犯)對曰
(舅犯)对曰
(jiù fàn) duì yuē
(Jiu Fan) sagte antwortend:
-----------------------------------
虞子羔可也
虞子羔可也
yú zi gāo kě yě
Yu Zigao kann man nehmen.
-----------------------------------
公曰
公曰
gōng yuē
Der Herzog sagte:
-----------------------------------
非 du 之 Feind 耶
fēi rǔ zhī chóu yé
Ist der nicht dein Feind?
-----------------------------------
對曰
对曰
duì yuē
(Jiu Fan) sagte antwortend:
-----------------------------------
君問誰為守者
君问谁为守者
jūn wèn shéi wéi shǒu zhě
Sie, mein Herzog, fragten, wer als Stadthalter geeignet ist.
-----------------------------------
非問臣之 Feind 也
非问臣之 Feind 也
fēi wèn chén zhī chóu yě
Sie fragten nicht, wer mein (des Beamten) Feind ist.
-----------------------------------
虞子羔見舅犯而謝之
虞子羔见舅犯而谢之
yú zi gāo jiàn jiù fàn ér xiè zhī
Yu Zigao besuchte Jiu Fan und bedankte sich
-----------------------------------
曰
曰
yuē
Er sagte:
-----------------------------------
幸赦臣之過
幸赦臣之过
xìng shè chén zhī guò
Ich bin glücklich, dass Sie mir (dem Beamten) meine Fehler vergeben.
-----------------------------------
_之於君
荐之于君
jiàn zhī yú jūn
und mich beim Fürsten empfehlen
-----------------------------------
得為西河守
得为西河守
dé wèi xī hé shǒu
(so dass ich die Berufung) zum Stadthalter am Westfluss bekomme.
-----------------------------------
舅犯曰
舅犯曰
jiù fàn yuē
Jiu Fan sagte:
-----------------------------------
荐子者公也
jiàn zi zhě gōng yě
Sie, mein Herr, zu empfehlen, ist eine öffentliche Angelegenheit.
-----------------------------------
怨子者私也
怨子者私也
yuàn zi zhě sī yě
Sie, mein Herr, zu hassen, ist eine Privatangelegenheit.
-----------------------------------
吾不以私事害義
吾不以私事害义
wú bù yǐ sī shì hài yì
Ich werde nicht wegen einer privaten Angelegenheit dem Allgemeinwohl schaden.
-----------------------------------
====第一百零六課====
第一百零六课
dì yī bǎi líng liù kè
Hundertsechste Lektion
-----------------------------------
錢-tang 江
钱-tang 江
qián táng jiāng
Der Qiantang-Fluss (Der Fluss mit dem Damm der Familie Qian)
-----------------------------------
[[w:zh:%E9%92%B1%E5%A1%98%E6%B1%9F|Wikipedia]]
钱-tang 江,古名 Zhe-江、Jian-江、Zhe-河,又称之江、折江、罗-sha-江,是中國 Zhe-江省第一大河,
qián táng jiāng, gǔ míng zhè jiāng, jiàn jiāng, zhè hé, yòu chēng zhī jiāng, zhé jiāng, luō shā jiāng, shì zhōng guó zhè jiāng shěng dì yī dà hé,
Der Qiantang-Fluss, alte Namen sind Zhèjiāng, Jiànjiāng, Zhèhé, ist auch bekannt als Zhījiāng, Zhéjiāng, Luōshājiāng.
Er ist der größte Fluss der chinesischen Provinz Zhejiang.
發源于安-hui 省黃山,
fā yuán yú ānhuī shěng huáng shān,
Er entspringt in der Provinz Anhui dem Huangshan.
流經安-hui、 Zhe-江二省,
liú jīng ān huī, zhè jiāng èr shěng,
Der Flussverlauf führt durch die beiden Provinzen Anhui und Zhejiang.
河流全长688千米。
hé liú quán zhǎng 688 qiān mǐ.
Die Gesamtlänge des Flusses beträgt 688 km.
钱-tang 江潮被誉为“天下第一潮”
qián táng jiāng cháo bèi yù wèi “tiān xià dì yī cháo”
Die Gezeitenwelle des Qiantang gilt als die "Größte Gezeitenwelle der Welt".
一般而言,錢-tang 江潮在農-Kalender 每月初一至初三、十五至十八出現,
yī bān ér yán, qián táng jiāng cháo zài nóng lì měi yuè chū yī zhì chū sān, shí wǔ zhì shí bā chū xiàn,
Allgemein gesprochen tritt die Gezeitenwelle des Qiantang-Flusses in jedem Monat des traditionellen chinesischen Kalerders vom ersten bis zum dritten und vom 15. bis zum 18. Tag in Erscheinung,
而农历八月十八的潮水最為 spektakulärer Anblick。
ér nóng lì bā yuè shí bā de cháo shuǐ zuì wéi zhuàng guān.
wobei die Gezeitenwelle am 18. Tag des achten Monats des traditionellen chinesischen Kalenders den spektakulärsten Anblick bietet.
-----------------------------------
錢-tang 江在 Zhe-江省
钱-tang 江在 Zhe-江省
qián táng jiāng zài zhè jiāng shěng
Der Qiantang-Fluss fließt in der Provinz Zhejiang.
-----------------------------------
Kan, Zhe 二山
kān zhě èr shān
Die beiden Berge Kan und Zhe
-----------------------------------
南北對 emporragen
南北对 emporragen
nán běi duì zhì
ragen in seinem Süden und Norden gegenüber empor.
-----------------------------------
江水既為山所束
江水既为山所束
jiāng shuǐ jì wèi shān suǒ shù
Das Flusswasser ist bereits durch die Berge gebündelt
-----------------------------------
又下有沙渚
又下有沙渚
yòu xià yǒu shā zhǔ
und anschließend gibt es eine Sandbank
-----------------------------------
teilen und behindern 江流
gé ài jiāng liú
die den Flußlauf teilt und behindert.
-----------------------------------
故起而為潮
故起而为潮
gù qǐ ér wéi cháo
darum steigt sein Pegel an und er wird zur Flutwelle.
-----------------------------------
势如 ein Berg
shì rú shān yuè
Ihre Erscheinung ist wie ein Berg.
-----------------------------------
聲如雷-getöse
声如雷-getöse
shēng rú léi tíng
Ihr Klang ist wie Donnergetöse.
-----------------------------------
八月望後
八月望后
bā yuè wàng hòu
Nach dem achten Vollmond
-----------------------------------
遠近之人多來_者
远近之人多来观者
yuǎn jìn zhī rén duō lái guān zhě
kommen die Menschen in großer Zahl von Fern und Nah, sie zu betrachten.
-----------------------------------
故 Zhe-江潮自古傳為奇景
故 Zhe-江潮自古传为奇景
gù zhè jiāng cháo zì gǔ chuán wéi qí jǐng
Darum wird die Zhejiang-Flutwelle seit alter Zeit als wunderbare Szene überliefert.
-----------------------------------
=== Frühling und Herbst des Lü Buwei ===
==== Wiederholungen ====
{| class="wikitable"
|-
! [https://ctext.org/lv-shi-chun-qiu/meng-xia-ji/zhs Erster Sommermonat, 2. Kapitel] !! [http://www.zeno.org/nid/20009211411 Übersetzung Richard Wilhelm]
|-
|故师之教也,不争轻重尊卑贫富,而争于道。 ||Die Lehrer fragten bei ihrer Belehrung nichts danach, ob der Schüler Einfluß hatte oder nicht, ob er vornehm oder gering, arm oder reich war, sondern sie fragten danach, wie er sich zur Wahrheit verhielt.
|-
|其人苟可,其事无不可,|| Ist der Mensch brauchbar, so werden seine Handlungen stets brauchbar sein.
|-
|所求尽得, || Was er sucht, wird er alles finden,
|-
|所欲尽成,|| was er wünscht, wird er alles vollenden.
|-
|此生于得圣人。 || Diese Erfolge kommen daher, daß man es erreicht, weise zu werden.
|-
|圣人生于 Mühe um 学。 || Ein Weiser wird man aber dadurch, daß man sich um seine Bildung Mühe gibt.
|-
|不 Mühe um 学而能为魁士名人者,未之尝有也。|| Es ist noch nie vorgekommen, daß jemand, der sich um seine Bildung nicht Mühe gab, ein großer Gelehrter und berühmter Mann geworden wäre.
|-
|Die Mühe um 学在于尊师, || Die Mühe um die Bildung besteht darin, daß man seinen Lehrer ehrt.
|-
|师尊则言信矣,道论矣。|| Ehrt man seinen Lehrer, so folgt man seinen Worten, und er teilt uns die Wahrheit mit.
|-
|故往教者不化,|| Wer auszieht, um andere zu belehren, kann keinen Einfluß gewinnen.
|-
|召师者不化, || Wer sich seinen Lehrer bestellt, wird nicht von ihm beeinflußt werden
|-
|自卑者不听, || Wer sich selbst entwürdigt, der findet kein Gehör;
|-
|卑师者不听。 || wer den Lehrer entwürdigt, der hört nicht auf ihn.
|-
|师 Methode ausüben 不化不听之术而以强教之,欲道之行、身之尊也,不亦远乎? || Wenn nun ein Lehrer eine Methode, durch die er weder Einfluß noch Gehör findet, ausübt und mit Gewalt den andern belehren will, um ihn anzuleiten zu einem ehrenwerten Benehmen, ist der nicht weit vom Ziel?
|-
|学者处不化不听之势,而以自行,欲名之显、身之安也,是怀 etwas Verfaultes 而欲香也,是入水而恶 naß werden 也。 || Wenn ein Lernender in einer Lage verweilt, die Beeinflussung und Hören unmöglich macht und durch dieses Benehmen einen berühmten Namen und ein gesichertes Leben zu erlangen wünscht, der macht es wie jemand, der etwas Verfaultes am Busen hält und duften möchte, oder wie jemand, der ins Wasser geht und nicht naß werden möchte.
|}
== Texte ==
=== [http://museum.marcopoloproject.org/2013/10/21/singapore-can-why-not-hong-kong-%e6%96%b0%e5%8a%a0%e5%9d%a1%e8%83%bd%e9%a6%99%e6%b8%af%e4%b8%ba%e4%bb%80%e4%b9%88%e4%b8%8d%e8%83%bd/ the marco polo project: 新加坡能香港为什么不能 – Singapore can – why not Hong Kong? (Auszug)] ===
{{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |香港和新加坡在亚洲四小龙中最为相似,不过,这些年新加坡突飞猛进。反观香港,原有与新加坡齐头并进的格局已经打破。
}}
[http://museum.marcopoloproject.org/author/ji-shuoming/ Ji Shuoming] [http://www.my1510.cn/article.php?id=103310 My 1510]
Among the four Asian Tigers, Hong Kong and Singapore are the most alike. However, in recent years, Singapore has leaped ahead. In contrast, Hong Kong, which used to be on a par with Singapore, has seen its model break down.
...
=== [https://ctext.org/analects/ens Analekte des Konfuzius] ===
{{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch | 子温而厉,威而不猛,恭而安。 }}
Übersetzung James Legge
The Master was mild, and yet dignified; majestic, and yet not fierce; respectful, and yet easy.
{{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch | 仲弓为季氏宰,问政。子曰:“先有司,赦小过,举贤才。”曰:“焉知贤才而举之?”曰:“举尔所知。尔所不知,人其舍诸?” }}
Übersetzung James Legge
Zhong Gong, being chief minister to the head of the Ji family, asked about government. The Master said, "Employ first the services of your various officers, pardon small faults, and raise to office men of virtue and talents." Zhong Gong said, "How shall I know the men of virtue and talent, so that I may raise them to office?" He was answered, "Raise to office those whom you know. As to those whom you do not know, will others neglect them?"
== [[s:en:Translation:Tao_Te_Ching | Tao Te Ching]] Kapitel 51 第五十一章 ==
{{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |
道生之,
德畜之,
物形之,
势成之。
是以万物
莫不尊道而贵德。
道之尊,
德之贵,
夫莫之命而常自然。
故道生之德畜之,
长之育之,
成之熟之,
养之复之;
生而不有,
为而不恃,
长而不宰,
是谓玄德。
}}
=== Übersetzung Richard Wilhelm ===
Der SINN erzeugt.
Das LEBEN nährt.
Die Umgebung gestaltet.
Die Einflüsse vollenden.
Darum ehren alle Wesen den SINN
und schätzen das LEBEN.
Der SINN wird geehrt,
das LEBEN wird geschätzt
ohne äußere Ernennung, ganz von selbst.
Also: der SINN erzeugt, das LEBEN nährt,
läßt wachsen, pflegt,
vollendet, hält,
bedeckt und schirmt.
=== Übersetzung [[s:en:Translation:Tao_Te_Ching | wikisource]] ===
The Dao conceives,
Virtue provisions,
Matters shape,
Movements empower.
Hence for the myriad things,
There is none that does not respect the Dao and honour Virtue.
Respect for the Dao,
Honour given to Virtue,
Are not commanded, yet they come about naturally.
Therefore the Dao conceives and Virtue provisions,
Leads and educates,
Empowers and ripens,
Raises and redeems.
Conceive and not possess,
Act and not dwell,
Lead and not dictate,
These are the intricacies of Virtue.
== Wiederholung Zeichen Tao Te Ching ==
{| class="wikitable"
|-
! Zeichen !! Pinyin !! Übersetzung
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |势}} || shi4 || Kraft, Einfluß, Potential, Moment, Zeichen, Geste, männliche Geschlechtsorgane
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |尊}} || zun1 || ehren, geehrter
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |育}} || yu4 || pflegen, erziehen
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |熟}} || shu2 || reif (Früchte)
|-
| {{:Vokabeltexte_Chinesisch/ Vorlage:Chinesisch |养}} || yang3 || aufziehen
|}
<noinclude>
{{Navigation zurückhochvor|
zurücktext=Lektion 560|
zurücklink=Vokabeltexte_Chinesisch/_Vokabellektionen/ Lektion 560|
hochtext=Buch Vokabellektionen|
hochlink=Vokabeltexte_Chinesisch/_Vokabellektionen|
vortext=Lektion 562|
vorlink=Vokabeltexte_Chinesisch/_Vokabellektionen/ Lektion 562}}
</noinclude>
l28qy9vpenekq7ilavqd6aqvy4ehie9
Musterentwürfe zum gerichtlichen Mahnverfahren/ Zusatzhinweise zum gerichtlichen Mahnverfahren
0
102119
1090616
1090613
2026-09-09T12:04:35Z
Raimund Barkam
58500
1090616
wikitext
text/x-wiki
Die hier angegebenen Zusatzhinweise beziehen sich auf das gerichtliche Mahnverfahren und wurden den Büchern "BGB = 79. Auflage 2017" und "ZPO = 57. Auflage 2016" / "ZPO = 58. Auflage 2017" entnommen. Ebenso werden hier mit Unterstützung der genannten Bücher, die hier genannten Paragraphen durch Angabe aktueller Paragraphen geändert oder ergänzt und somit den gesetzgeberischen Regelungen angepasst und vervollständigt. Die Nachfolgend aufgeführten Zusatzhinweise wurden den beiden genannten Büchern entnommen und sollen die Paragraphen mit den Angaben lt. Gesetzestexten ergänzen:
:''' Paragraphen und Text lt. Buch ZPO - Zivilprozessordnung'''
ISBN 978-3-423-53106-1 (dtv) / ISBN 978-3-406-77913-8 (C. H. Beck)
::::::<Font Size="5"> '''1 Zivilprozessordnung'''</Font>
::::::In der Fassung der Bekanntmachung vom Dezember2005<sup>1)</sup>
:::::::(BGB1. I S.3202, ber. 2006 I S. 431 und 2007 I S. 1781)
<Font Size="3">                                                                  '''FNA 310-4'''
zuletzt geänd. durch Art. 14 G zur Modernisierung des notariellen Berufsrechts und zur Änd. weiterer<br>
Vorschriften v. 25.6.2021 (BGB1. I S. 2154)
<Font Size="4">                                                           '''Inhaltsübersicht'''
:::::::'''Buch 1. Allgemeine Vorschriften'''
::::::::: Abschnitt 1. Gerichte
:::::: Titel 1. Sachliche Zuständigkeit der Gerichte und Wertvorschriften
§   1        Sachliche Zuständigkeit<br>
§   2        Bedeutung des Wertes<br>
§   3        Wertfestsetzung nach freiem Ermessen<br>
§   4        Wertberechnung Nebenforderungen<br>
§   5        Mehrere Ansprüche<br>
§   6        Besitz; Sicherstellung; Pfandrecht<br>
§   7        Grunddienstbarkeit<br>
§   8        Pacht- oder Mietverhältnis<br>
§   9        Wiederkehrende Nutzungen oder Leistungen<br>
§   10        (weggefallen)<br>
§   11        Bindende Entscheidung über Unzuständigkeit<br>
:::::: Titel 2. Gerichtsstand
§   12        Allgemeiner Gerichtsstand; Begriff<br>
§   13        Allgemeiner Gerichtsstand des Wohnsitzes<br>
§   14        (weggefallen)<br>
§   15        Allgemeiner Gerichtsstand für exterritoriale Deutsche<br>
§   16        Allgemeiner Gerichtsstand wohnungsloser Personen<br>
§   17        Allgemeiner Gerichtsstand juristischer Personen<br>
§   18        Allgemeiner Gerichtsstand des Fiskus<br>
§   19        Mehrere Gerichtsbezirke am Behördensitz<br>
§   19a      Allgemeiner Gerichtsstand des Insolvenzverwalters<br>
§   19b      Ausschließlicher Gerichtsstand bei restrukturierungsbezogenen Klagen;            Verordnungsermächtigung<br>
§   20        Besonderer Gerichtsstand des Aufenthaltsorts<br>
§   21        Besonderer Gerichtsstand der Niederlassung<br>
§   22        Besonderer Gerichtsstand der Mitgliedschaft<br>
§   23        Besonderer Gerichtsstand des Vermögens und des Gegenstands<br>
§   24        Ausschließlicher dringlicher Gerichtsstand<br>
§   25        Dinglicher Gerichtsstand des Sachzusammenhanges<br>
§   26        Dinglicher Gerichtsstand für persönliche Klagen<br>
§   27        Besonderer Gerichtsstand der Erbschaft<br>
§   28        Erweiterter Gerichtsstand der Erbschaft<br>
§   29        Besonderer Gerichtsstand des Erfüllungsorts<br>
§   29a      Ausschließlicher Gerichtsstand bei Miet- und Pachträumen<br>
§   29b      (weggefallen)<br>
§   29c      Besonderer Gerichtsstand für Haustürgeschäfte<br>
§   30        Besonderer Gerichtsstand bei Beförderungen <br>
§   30a      Gerichtsstand bei Bergungsansprüchen<br>
§   31        Besonderer Gerichtsstand der Vermögensverwaltung<br>
§   32        Besonderer Gerichtsstand der unerlaubten Handlung<br>
§   32a      Ausschließlicher Gerichtsstand der Umwelteinwirkung<br>
§   32b      Ausschließlicher Gerichtsstand bei falschen, irreführenden oder unterlassenen öffentlichen Kapitalmarktinformationen<br>
§   32c      Ausschließlicher Gerichtsstand bei Musterfeststellungsverfahren<br>
§   33        Besonderer Gerichtsstand der Widerlege<br>
§   34        Besonderer Gerichtsstand des Hauptprozesses<br>
§   35        Wahl unter mehreren Gerichtsständen<br>
$   36        Gerichtliche Bestimmung der Zuständigkeit<br>
§   37        Verfahren bei gerichtlicher Bestimmung<br>
:::::: Titel 3. Vereinbarung über die Zuständigkeit der Gerichte
§   38        Zugelassene Gerichtsstandsvereinbarung<br>
§   39        Zuständigkeit infolge regenloser Verhandlung<br>
§   40        Unwirksame und unzulässige Gerichtsstandsvereinbarung<br>
:::::: Titel 4. Ausschließung und Ablehnung der Gerichtspersonen
§   41        Ausschluss von der Ausübung des Richteramtes<br>
§   42        Ablehnung eines Richters<br>
§   43        Verlust des Ablehnungsrechts<br>
§   44        Ablehnungsgesuch<br>
§   45        Entscheidung über das Ablehnungsgesuch<br>
§   46        Entscheidung des Rechtsmittel<br>
§   47        Unaufschiebbare Amtshandlungen<br>
§   48        Selbstablehnung: Ablehnung von Amts wegen<br>
§   49        Urkundsbeamte <br>
::::::: Abschnitt 2. Parteien
:::::: Titel 1. Parteifähigkeit; Prozessfähigkeit
§   50        Parteifähigkeit<br>
§   51        Prozessfähigkeit; gesetzliche Vertretung, Prozessführung<br>
§   52        Umfang der Prozessfähigkeit<br>
'''[bis 31.12.2022:]'''<br>
§   53         Prozessunfähigkeit bei Betreuung oder Pflegeschaft<br>
'''[bis 1.1.2023:]'''<br>
<i>§   53        Prozessfähigkeit bei rechtlicher Betreuung</i><br>
§   54        Besondere Ermächtigung zu Prozesshandlungen<br>
§   55        Prozessfähigkeit von Ausländern<br>
§   56        Prüfung von Amts wegen<br>
§   57        Prozesspfleger<br>
§   58        Prozesspfleger bei herrenlosem Grundstück oder Schiff<br>
:::::: Titel 2. Streitgenossenschaft
§   59        Streitgenossenschaft bei Rechtsgemeinschaft oder Identität des Grundes<br>
§   60        Streitgenossenschaft bei Gleichartigkeit der Ansprüche<br>
§   61        Wirkung der Streitgenossenschaft<br>
§   62        Notwendige Streitgenossenschaft<br>
§   63        Prozessbetrieb; Ladungen<br>
:::::: Titel 3. Beteiligung Dritter am Rechtsstreit
§   64        Hauptintervention<br>
§   65        Aussetzung des Hauptprozesses<br>
§   66        Nebenintervention<br>
§   67        Rechtsstellung des Nebenintervenienten<br>
§   68        Wirkung der Nebenintervention<br>
§   69        Streitgenössische Nebenintervention<br>
§   70        Beitritt des Nebenintervenienten<br>
§   71        Zwischenstreit über Nebenintervention<br>
§   72        Zulässigkeit der Streitverkündung<br>
§   73        Form der Streitverkündung<br>
§   74        Wirkung der Streitverkündung<br>
§   75        Gläubigerstreit<br>
§   76        Urheberbenennung bei Besitz<br>
§   77        Urheberbenennung bei Eigentumsbeeinträchtigung<br>
:::::: Titel 4. Prozessbevollmächtigte und Beistände
§   78        Anwaltsprozess<br>
§   78a     (weggefallen)<br>
§   78b     Notanwalt<br>
§   78c     Auswahl des Rechtsanwalts<br>
§   79        Parteiprozess<br>
§   80        Prozessvollmacht<br>
§   81        Umfang der Prozessvollmacht<br>
§   82        Geltung für Nebenverfahren<br>
§   83        Beschränkung der Prozessvollmacht<br>
§   84        Mehrere Prozessbevollmächtigte<br>
§   85        Wirkung der Prozessvollmacht<br>
§   86        Fortbestand der Prozessvollmacht<br>
§   87        Erlöschen der vollmacht<br>
§   88        Mangel der Vollmacht<br>
§   89        vollmachtloser Vertreter<br>
§   90        Beistand<br>
:::::: Titel 5. Prozesskosten
§   91        Grundsatz und Umsatz der Kostenpflicht<br>
§   91a     Kosten bei Erledigung der Hauptsache<br>
§   92        Kosten bei teilweisen Obsiegen<br>
§   93        Kosten bei sofortigem Anerkenntnis<br>
§   93a     (weggefallen)<br>
§   93b     Kosten bei Räumungsklagen<br>
§   94        Kosten bei übergegangenem Anspruch<br>
§   95        Kosten bei Säumnis oder Verschulden<br>
§   96        Kosten erfolgloser Angriffs- oder Verteidigungsmittel<br>
§   97        Rechtsmittelkosten<br>
§   98        Vergleichskosten<br>
§   99        Anfechtung von Kostenentscheidungen<br>
§ 100        Kosten bei Streitgenossen<br>
§ 101        Kosten einer Nebenintervention<br>
§ 102       (weggefallen)<br>
§ 103        Kostenfestsetzungsgrundlage; Kostenfestsetzungsantrag<br>
§ 104        Kostenfestsetzungsverfahren<br>
§ 105        Vereinfachter Kostenfestsetzungsbeschluss<br>
§ 106        Verteilung nach Quoten<br>
§ 107        Änderung nach Streitwertfestsetzung<br>
:::::: Titel 6. Sicherheitsleistung
§ 108        Art und Höhe der Sicherheit<br>
§ 109        Rückgabe der Sicherheit<br>
§ 110        Prozesskostensicherheit<br>
§ 111        Nachhaltige Prozesskostensicherheit<br>
§ 112        Höhe der Prozesskostensicherheit<br>
§ 113        Fristbestimmung für Prozesskostensicherheit<br>
:::::: Titel 7. Prozesskostenhilfe
§ 114        Voraussetzungen<br>
§ 115        Einsatz von Einkommen und Vermögen<br>
§ 116        Partei kraft Amtes; juristische Person; parteifähige Vereinigung<br>
§ 117        Antrag<br>
§ 118        Bewilligungsverfahren<br>
§ 119        Bewilligung<br>
§ 120        Festsetzung von Zahlungen<br>
§ 120a     Änderung der Bewilligung<br>
§ 121        Beiordnung eines Rechtsanwalts<br>
§ 122        Wirkung der Prozesskostenhilfe<br>
§ 123        Kostenerstattung<br>
§ 124        Aufhebung der Bewilligung<br>
§ 125        Einbeziehung der Kosten<br>
§ 126        Beitreibung der Rechtsanwaltskosten<br>
§ 127        Entscheidungen<br>
::::::: Abschnitt 3. Verfahren
:::::: Titel 1. Mündliche Verhandlung
§ 128        Grundsatz der Mündlichkeit; schriftliches Verfahren<br>
§ 128a      Verhandlung im Wege der Bild- und Tonübertragung<br>
§ 129        Vorbereitende Schriftsätze<br>
§ 129a     Anträge und Erklärungen zu Protokoll<br>
§ 130        Inhalt der Schriftsätze<br>
§ 130a      Elektronisches Dokument<br>
§ 130b      Gerichtliches elektronisches Instrument<br>
§ 130c      Formulare: Verordnungsermächtigung<br>
'''''[ab 1.1.2022:]'''''<br>
§ 130d      ''Nutzungspflicht für Rechtsanwälte und Behörden''<br>
§ 131        Beifügung von Urkunden<br>
§ 132        Fristen für Schriftsätze<br>
§ 133        Abschriften<br>
§ 134        Einsicht von Urkunden<br>
§ 135        Mitteilung von Urkunden unter Rechtsanwälten<br>
§ 136        Prozessleistung durch Vorsitzenden<br>
§ 137        Gang der mündlichen Verhandlung<br>
§ 138        Erklärungspflicht über Tatsachen; Wahrheitspflicht<br>
§ 139        Materielle Prozessleistung<br>
§ 140        Beanstandung von Prozessleistung oder Fragen<br>
§ 141        Anordnung des persönlichen Erscheinens<br>
§ 142        Anordnung der Urkundenvorlegung<br>
§ 143        Anordnung der Aktenübermittlung<br>
§ 144        Augenschein; Sachverständige<br>
§ 145        Prozesstrennung<br>
§ 146        Beschränkung auf einzelne Angriffs- und Verteidigungsmittel<br>
§ 147        Prozessverbindung<br>
§ 148        Aussetzung bei Vortrefflichkeit<br>
§ 149        Aussetzung bei Verdacht einer Straftat<br>
§ 150        Aufhebung von Trennung, Verbindung oder Aussetzung<br>
§ 151        (weggefallen)<br>
§ 152        Aussetzung bei Eheaufhebungsantrag<br>
§ 153        Aussetzung bei Vaterschaftsanfechtungsklage<br>
§ 154        Aussetzung bei Ehe- oder Kindschaftsstreit<br>
§ 155        Aufhebung der Aussetzung bei Verzögerung<br>
§ 156        Wiedereröffnung der Verhandlung<br>
§ 157        Untervertretung in der Verhandlung<br>
§ 158        Entfernung infolge Prozessleitungsanordnung<br>
§ 159        Protokollaufnahme<br>
§ 160        Inhalt des Protokolls<br>
§ 160a      Vorläufige Protokollaufzeichnung<br>
§ 161        Entbehrliche Feststellungen<br>
§ 162        Genehmigung des Protokolls<br>
§ 163        Wiedereröffnung der Verhandlung<br>
§ 164        Protokollberechtigung<br>
§ 165        Beweiskraft des Protokolls<br>
:::::::::Titel 2. Verfahren bei Zustellungen
:::::::Untertitel 1. Zustellungen von Amts wegen
§ 166        Zustellung<br>
§ 167        Rückwirkung der Zustellung<br>
§ 168        Aufgaben der Geschäftsstelle<br>
§ 169        Bescheinigung des Zeitpunktes der Zustellung; Beglaubigung<br>
§ 170        Zustellung an Vertreter<br>
'''''[ab 1.1.2023:]'''''<br>
§ 170a      ''Zustellung bei rechtlicher Betreuung''<br>
§ 171        Zustellung an Bevollmächtigte<br>
§ 172        Zustellung an Prozessbevollmächtigte<br>
§ 173        Zustellung durch Aushändigung an der Amtsstelle<br>
§ 174        Zustellung gegen Empfangsbekenntnis oder automatisierte Eingangsbestätigung<br>
§ 175        Zustellung durch Einschreiben mit Rückschein<br>
§ 176        Zustellungsauftrag<br>
§ 177        Ort der Zustellung<br>
§ 178        Ersatzzustellung in der Wohnung, in Geschäftsräumen oder Einrichtungen<br>
§ 179        Zustellung bei verweigerter Annahme<br>
§ 180        Ersatzzustellung durch Einlegen in den Briefkasten<br>
§ 181        Ersatzzustellung durch Niederlegung<br>
§ 182        Zustellungsurkunde<br>
§ 183        Zustellung im Ausland<br>
§ 184        Zustellungsbevollmächtigter: Zustellung durch Aufgabe zur Post<br>
§ 185        Öffentliche Zustellung<br>
§ 186        Bewilligung und Ausführung der öffentlichen Zustellung<br>
§ 187        Veröffentlichung der Benachrichtigung<br>
§ 188        Zeitpunkt der öffentlichen Zustellung<br>
§ 189        Heilung von Zustellungsmängeln<br>
§ 190        Einheitliche Zustellungsformulare<br>
:::::::Untertitel 2. Zustellungen auf Betreiben der Parteien
§ 191        Zustellung<br>
§ 192        Zustellung durch Gerichtsvollzieher<br>
§ 193        Ausführung der Zustellung<br>
§ 194        Zustellungsauftrag<br>
§ 195        Zustellung von Anwalt zu Anwalt<br>
§§ 195a-213a      weggefallen<br>
:::::::::Titel 3. Ladungen, Termine und Fristen
§ 214        Ladung zum Termin<br>
§ 215        Notwendiger Inhalt der Ladung zur mündlichen Verhandlung<br>
§ 216        Terminbestimmung<br>
§ 217        Ladungsfrist<br>
§ 218        Entbehrlichkeit der Ladung<br>
§ 219        Terminsort<br>
§ 220        Aufruf der Sache; versäumter Termin<br>
§ 221        Fristbeginn<br>
§ 222        Fristberechnung<br>
§ 223        (weggefallen)<br>
§ 224        Fristkürzung: Fristverlängerung<br>
§ 225        Verfahren bei Friständerung<br>
§ 226        Abkürzung von Zwischenfristen<br>
§ 227        Terminsänderung<br>
§ 228        (weggefallen)<br>
§ 229        Terminsänderung<br>
:::::::::Titel 4. Folgen der Versäumnis Rechtsbehelfsbelehrung: Wiedereinsetzung in den vorigen Stand
§ 230        Allgemeine Versäumungserfolge<br>
§ 231        Keine Androhung: Nachholung der Prozesshandlung<br>
§ 232        Behelfsbelehrung<br>
§ 233        Terminsänderung<br>
§ 234        Wiedereinsetzungsfrist<br>
§ 235        (weggefallen)<br>
§ 236        Wiedereinsetzungsantrag<br>
§ 237        Zuständigkeit für Wiedereinsetzung<br>
§ 238        Wiedereinsetzungsantrag<br>
:::::::::Titel 5. Unterbrechung und Aussetzung des Verfahrens
§ 239        Unterbrechung durch Tod der Partei<br>
§ 240        Unterbrechung durch Insolvenzverfahren<br>
§ 241        Unterbrechung durch Prozessunfähigkeit<br>
§ 242        Unterbrechung durch Nachfolge<br>
§ 243        Aufnahme bei Nachlasspflegschaft und Testamentsvollstreckung<br>
§ 244        Unterbrechung durch Anwaltsverlust<br>
§ 245        Unterbrechung durch Stillstand der Rechtspflege<br>
§ 246        Aussetzung bei Vertretung durch Prozessbevollmächtigten<br>
§ 247        Aussetzung bei abgeschnittenen Verkehr<br>
§ 248        Verfahren bei Aussetzung<br>
§ 249        Wirkung von Unterbrechung und Aussetzung<br>
§ 250        Form von Aufnahme und Anzeige<br>
§ 251        Ruhen des Verfahrens<br>
§ 251a      Säumnis beider Parteien; Entscheidung nach Lage der Akten<br>
§ 252        Rechtsmittel bei Aussetzung<br>
:::::::'''Buch 2. Verfahren im ersten Rechtszug'''
::::::::: Abschnitt 1. Verfahren vor den Landgerichten
:::::::::Titel 1. Verfahren bis zum Urteil
§ 253        Klageschrift<br>
§ 254        Stufenklage<br>
§ 255        Fristbestimmung im Urteil<br>
§ 256        Feststellungsklage<br>
§ 257        Klage auf künftige Zahlung oder Räumung<br>
§ 258        Klage auf wiederkehrende Leistungen<br>
§ 259        Klage wegen Besorgnis nicht rechtzeitigen Leistung<br>
§ 260        Anspruchshäufung<br>
§ 261        Rechtshängigkeit<br>
§ 262        Sonstige Wirkungen der Rechtshängigkeit<br>
§ 263        Klageänderung<br>
§ 264        Keine Klageänderung<br>
§ 265        Veräußerung oder Abtretung der Streitsache<br>
§ 266        Veräußerung eines Grundstücks<br>
§ 267        Vermutete Einwilligung in die Klageänderung<br>
§ 268        Unanfechtbarkeit der Entscheidung<br>
§ 269        Klagerücknahme<br>
§ 270        Zustellung; formlose Mitteilung<br>
§ 271        Zustellung der Klageschrift<br>
§ 272        Bestimmung der Verfahrensweise<br>
§ 273        Vorbereitung des Termins<br>
§ 274        Ladung der Parteien; Einlassungsfrist<br>
§ 275        Früher erster Termin<br>
§ 276        Schriftliches Vorverfahren<br>
§ 277        Klageerwiderung: Replik<br>
§ 278        Gütliche Streitbeilegung, Güterverhandlung, Vergleich<br>
§ 278a      Mediation, außergerichtliche Konfliktbeilegung<br>
§ 279        Mündliche Verhandlung<br>
§ 280        Abgesonderte Verhandlung über Zuverlässigkeit der Klage<br>
§ 281        Verweisung bei Unzuständigkeit<br>
§ 282        Rechtzeitigkeit des Vorbringen<br>
§ 283        Schriftsatzfrist für Erklärungen zur Vorbringen des Gegners<br>
§ 283a      Sicherungsanordnung<br>
§ 284        Schriftsatzfrist für Erklärungen zum Vorbringen des Gegners<br>
§ 285        Verhandlung nach Beweisaufnahme<br>
§ 286        Freie Beweiswürdigung<br>
§ 287        Schadensermittlung; Höhe der Forderung<br>
§ 288        Gerichtliches Geständnis<br>
§ 289        Zusätze beim Geständnis<br>
§ 290        Widerruf des Geständnisses<br>
§ 291        Offenkundige Tatsachen<br>
§ 292        Gesetzliche Vermutungen<br>
§ 292a      (weggefallen)<br>
§ 293        Fremdes Recht; Gewohnheitsrecht; Statuten<br>
§ 294        Glaubhaftmachung<br>
§ 295        Verfahrensrügen<br>
§ 296        Zurückweisung verspäteten Vorbringens<br>
§ 296a      Vorbringen nach Schluss der mündlichen Verhandlung<br>
§ 297        Form der Antragstellung<br>
§ 298        Aktenausdruck<br>
§ 298a      Elektronische Akte; Verordnungsermächtigung<br>
§ 299        Akteneinsicht; Abschriften<br>
§ 299a      Datenträgerarchiv<br>
:::::::::Titel 2. Urteil
§ 300        Endurteil<br>
§ 301        Teilurteil<br>
§ 302        Vorbehaltsurteil<br>
§ 303        Zwischenurteil<br>
§ 304        Zwischenurteil über den Grund<br>
§ 305        Urteil unter Vorbehalt erbrechtlich beschränkter Haftung<br>
§ 305a      Urteil unter Vorbehalt seerechtlich beschränkter Haftung<br>
§ 306        Verzicht<br>
§ 307        Anerkenntnis<br>
§ 308        Bindung an die Parteianträge<br>
§ 309        Erkennende Richter<br>
§ 310        Termin der Urteilsverkündung<br>
§ 311        Form der Urteilsverkündung<br>
§ 312        Anwesenheit der Parteien<br>
§ 313        Form und Inhalt des Urteils<br>
§ 313a      Weglassen von Tatbestand und Entscheidungsgründen<br>
§ 313b      Versäumnis-, Anerkenntnis- und Verzichtsurteil<br>
§ 314        Beweiskraft des Tatbestandes<br>
§ 315        Unterschrift des Richters<br>
§ 316        (weggefallen)<br>
§ 317        Urteilszustellung und -ausfertigung<br>
§ 318        Bindung des Gerichts<br>
§ 319        Berichtigung des Urteils<br>
§ 320        Berichtigung des Tatbestands<br>
§ 321        Ergänzung des Urteils<br>
§ 321a      Abhilfe bei Verletzung des Anspruchs auf rechtliches Gehör<br>
§ 322        Materielle Rechtskraft<br>
§ 323        Abänderung von Urteilen<br>
§ 323a      Abänderung von Vergleichen und Urkunden<br>
§ 323b      Verschärfte Haftung<br>
§ 324        Nachforderungsklage zur Sicherheitsleistung<br>
§ 325        Subjektive Rechtskraftwirkung<br>
§ 325a      Feststellungswirkung des Musterentscheids<br>
§ 326        Rechtskraft bei Nacherbfolge<br>
§ 327        Rechtskraft bei Testamentsvollstreckung<br>
§ 328        Anerkennung ausländischer Urteile-<br>
§ 329        Beschlüsse und Verfügungen<br>
:::::::::Titel 3. Versäumnisurteil
§ 330        Versäumnisurteil gegen den Kläger<br>
§ 331        Versäumnisurteil gegen den Beklagten<br>
§ 331a      Entscheidung nach Aktenlage<br>
§ 332        Begriff des Verhandlungstermins<br>
§ 333        Nichtverhandeln der erscheinenden Partei<br>
§ 334        Unvollständiges Verhandeln<br>
§ 335        Unzulässigkeit einer Versäumniserscheinung<br>
§ 336        Rechtsmittel bei Zurückweisung<br>
§ 337        Vertagung von Amts wegen<br>
§ 338        Einspruch<br>
§ 339        Einspruchsfrist<br>
§ 340        Einspruchsschrift<br>
§ 340a      Zustellung der Einspruchsschrift<br>
§ 341        Einspruchsprüfungbr>
§ 341a      Einspruchstermin<br>
§ 342        Wirkungen des zulässigen Einspruchs<br>
§ 343        Entscheidung nach Einspruch<br>
§ 344        Versäumniskosten<br>
§ 345        Zweites Versäumnisurteil<br>
§ 346        Verzicht und Zurücknahme des Einspruchs<br>
§ 347        Verfahren bei Widerklage und Zwischenstreit<br>
:::::::::Titel 4. Verfahren vor dem Einzelrichter
§ 348        Originärer Einzelrichter<br>
§ 348a      Obligatorischer Einzelrichter<br>
§ 349        Vorsitzender der Kammer für Handelssachen<br>
§ 350        Rechtsmittel<br>
§ 351-354 (weggefallen)<br>
:::::::::Titel 5. Allgemeine Vorschriften über die Beweisaufnahme
§ 355        Unmittelbarkeit der Beweisaufnahme<br>
§ 356        Beibringungsfrist<br>
§ 357        Parteiöffentlichkeit<br>
§ 357a      (weggefallen)<br>
§ 358        Notwendigkeit eines Beweisschlusses<br>
§ 358a      Beschwerdeschluss und Beweisaufnahme vor mündlicher Verhandlung<br>
§ 359        Inhalt des Beweisschlussses<br>
§ 360        Änderung des Beweisschlusses<br>
§ 361        Beweisaufnahme durch beauftragten Richter<br>
§ 362        Beweisaufnahme durch ersuchten Richter<br>
§ 363        Beweisaufnahme im Ausland<br>
§ 364        Parteimitwirkung bei Beweisaufnahme im Ausland<br>
§ 365        Abgabe durch beauftragten oder ersuchten Richter<br>
§ 366        Zwischenstreit<br>
§ 367        Ausbleiben der Partei<br>
§ 368        Neuer Beweistermin<br>
§ 369        Ausländische Beweisaufnahme<br>
§ 370        Fortsetzung der mündlichen Verhandlung<br>
:::::::::Titel 6. Beweis durch Augenschein
§ 371        Beweis durch Augenschein<br>
§ 371a      Beweiskraft elektronischer Dokumente<br>
§ 371b      Beweiskraft gescannter öffentlicher Urkunden<br>
§ 372        Beweisaufnahme
§ 372a      Untersuchungen zur Feststellung der Abstammung<br>
:::::::::Titel 7. Zeugenbeweis
§ 373        Beweisantritt<br>
§ 374        (weggefallen)<br>
§ 375        Beweisaufnahme durch beauftragten oder ersuchten Richter<br>
§ 376        Vernehmung bei Amtsverschwiegenheit<br>
§ 377        Zeugenladung<br>
§ 378        Aussageerleichternde Unterlagen<br>
§ 379        Auslagenvorschuss<br>
§ 380        Folgen des Ausbleiben des Zeugen<br>
§ 381        Genügende Entschuldigung des Ausbleibens<br>
§ 382        Vernehmung an bestimmten Orten<br>
§ 383        Zeugnisverweigerung aus persönlichen Gründen<br>
§ 384        Zeugnisverweigerung aus sachlichen Gründen<br>
§ 385        Ausnahmen vom Zeugnisverweigerungsrecht<br>
§ 386        Erklärung der Zeugnisverweigerung<br>
§ 387        Zwischenstreit über Zeugnisverweigerung<br>
§ 388        Zwischenstreit über schriftliche Zeugnisverweigerung<br>
§ 389        Zeugnisverweigerung vor beauftragtem oder ersuchtem Richer<br>
§ 390        Folgen der Zeugnisverweigerung<br>
§ 391        Zeugenbeeidigung<br>
§ 392        Nacheid; Eidesnorm<br>
§ 393        Uneidliche Wahrnehmung<br>
§ 394        Einzelvernehmung<br>
§ 395        Wahrheitsermahnung, Vernehmung zur Person<br>
§ 396        Vernehmung zur Sache<br>
§ 397        Fragerecht der Parteien<br>
§ 398        Wiederholte und nachträgliche Vernehmung<br>
§ 399        Verzicht auf Zeugen<br>
§ 400        Befugnisse des mit der Beweisaufnahme betrauten Richters<br>
§ 401        Zeugenentschädigung<br>
:::::: Titel 8. Beweis durch Sachverständige
§ 402        Anwendbarkeit der Vorschriften für Zeugen<br>
§ 403        Beweisantritt<br>
§ 404        Sachverständigenauswahl<br>
§ 404a      Vorläufige Leitung der Tätigkeit des Sachverständigen<br>
§ 405        Auswahl durch den mit der Beweisaufnahme betrauten Richter<br>
§ 406        Ablehnung eines Sachverständigen<br>
§ 407        Pflicht zur Erstattung des Gutachtens<br>
§ 407a      Weitere Pflichten des Sachverständigen<br>
§ 408        Gutachtenverweigerungsrecht<br>
§ 409        Folgen des Ausbleibens oder der Gutachterverweigerung<br>
§ 410        Sachverständigenbeeidigung<br>
§ 411        Schriftliches Gutachten<br>
§ 411a      Verwertung von Sachverständigengutachten aus anderen Verfahren<br>
§ 412        Neues Gutachten<br>
§ 413        Sachverständigenvergütung<br>
§ 414        Sachverständige Zeugen<br>
:::::: Titel 9. Beweis durch Urkunden
§ 415        Beweiskraft öffentliche Urkunden über Erklärungen<br>
§ 416        Beweiskraft von Privaturkunden<br>
§ 417        Beweiskraft öffentlicher Urkunden über amtliche Anordnung, Verfügung oder Entscheidung<br>
§ 418        Beweiskraft öffentlicher Urkunden mit anderem Inhalt<br>
§ 419        Beweiskraft mangelbehafteter Urkunden<br>
§ 420        Vorlegung durch Beweisführer; Beweisantritt<br>
§ 421        Vorlegung durch den Gegner; Beweisantritt<br>
§ 422        Vorlegungspflicht des Gegners nach bürgerlichem Recht<br>
§ 423        Vorlegungspflicht des Gegners bei Bezugnahme<br>
§ 424        Antrag bei Vorlegung durch<br>
§ 425        Anordnung durch Vorlegung durch Gegner<br>
§ 426        Vernehmung des Gegners über den Verbleib<br>
§ 427        Folgen der Nichtvorlegung durch Gegner<br>
§ 428        Vorlegung durch Dritte; Beweisantriss<br>
§ 429        Vorlegungspflicht Dritter
§ 430        Antrag bei Vorlegung durch Dritte<br>
§ 431        Vorlegungsfrist bei Vorlegung durch Dritte<br>
§ 432        Vorlegung durch Behörden oder Beamte: Beweisantritt<br>
§ 433        (weggefallen)<br>
§ 434        Vorlegung vor beauftragtem oder ersuchtem Richter<br>
§ 435        Vorlegung öffentlicher Urkunden in Urschrift oder beglaubigter Abschrift<br>
§ 436        Verzicht nach Vorlegung<br>
§ 437        Echtheit inländischer öffentlicher Urkunden<br>
§ 438        Echtheit ausländischer öffentlicher Urkunden<br>
§ 439        Erklärung über Echtheit von Pribaturkunden<br>
§ 440        Beweis der Echtheit von Pribaturkunden<br>
§ 441        Schriftvergleichung<br>
§ 442        Würdigung der Schriftvergleichung<br>
§ 443        Verwahrung verdächtiger Urkunden<br>
§ 444        Folgen der Bereitung einer Urkunde<br>
:::::: Titel 10. Beweis durch Urkunden
§ 445        Vernehmung des Gegners: Beweisantritt<br>
§ 446        Weigerung des Gegners<br>
§ 447        Vernehmung der Beweispflichtigen Partei auf Antrag<br>
§ 448        Vernehmung von Amts wegen<br>
§ 449        Vernehmung von Streitgenossen<br>
§ 450        Besweisschluss<br>
§ 451        Ausführung der Vernehmung<br>
§ 452        Beeidigung der Partei<br>
§ 453        Beweiswürdigung bei Parteivernehmung <br>
§ 454        Ausbleiben der Partei <br>
§ 455        Prozessunfähige <br>
§§ 456-477 (weggefallen) <br>
:::::: Titel 11. Abnahme von Eiden und Bekräftigungen
§ 478        Eidesleistung in Person <br>
§ 479        Eidesleistung vor beauftragtem oder ersuchtem Richter <br>
§ 480        Eidesbelehrung <br>
§ 481        Eidesleistung: Eidesformel <br>
§ 482        (weggefallen) <br>
§ 483        Eidesleistung sprach- oder hörbehinderter Personen <br>
§ 484        Eidesgleiche Bekräftigung <br>
:::::: Titel 12. Selbständiges Beweisverfahren
§ 485        Zulässigkeit <br>
§ 486        Zuständiges Gericht <br>
§ 487        Inhalt des Antrages <br>
§§ 488,489 (weggefallen) <br>
§ 490        Entscheidung über den Antrag <br>
§ 491        Ladung des Gegners <br>
§ 492        Beweisaufnahme <br>
§ 493        Benutzung im Prozess <br>
§ 494        Unbekannter Gegner <br>
§ 494a      Frist zur Klageerhebung<br>
::::::::: Abschnitt 2. Verfahren vor den Amtsgerichten
§ 495        Anzuwendende Vorschriften <br>
§ 496        Einrichtung von Schriftsätzen; Erklärungen zu Protokoll <br>
§ 497        Ladungen <br>
§ 498        Zustellung des Protokolls über die Klage <br>
§ 499        Belehrungen <br>
§§ 499a-503 (weggefallen) <br>
§ 504        Hinweis bei Unzuständigkeit des Amtsgerichts <br>
§ 505        (weggefallen) <br>
§ 506        Nachträgliche sachliche Unzuständigkeit <br>
§§ 507-509 (weggefallen) <br>
§ 510        Erklärung über Urkunden <br>
§ 510a      Inhalt des Protokolls <br>
§ 510b      Urteil und Vornahme einer Handlung <br>
§ 510c      (weggefallen) <br>
:::::::'''Buch 3. Rechtsmittel'''
:::::::Abschnitt 1. Berufung
§ 511        Standhaftigkeit der Berufung <br>
§ 512        Vorentscheidungen im ersten Rechtszug <br>
§ 513        Berufungsgründe <br>
§ 514        Versäumnisurteile <br>
§ 515        Verzicht auf Berufung <br>
§ 516        Zurücknahme der Berufung <br>
§ 517        Berufungsfrist <br>
§ 518        Berufungsfrist bei Urteilsergänzung <br>
§ 519        Berufungsschrift <br>
§ 520        Berufungsbegründung <br>
§ 521        Zustellung der Berufungsschrift und -begründung <br>
§ 522        Zulässigkeitsprüfung; Zurückweisungsbeschluss <br>
§ 523        Terminsbestimmung <br>
§ 524        Anschlussberufung <br>
§ 525        Allgemeine Verfahrensgrundsätze <br>
§ 526        Entscheidender Richter <br>
§ 527        Vorbereitender Einzelrichter <br>
§ 528        Bindung an die Berufungsanträge <br>
§ 529        Prüfungsumfang des Berufungsgerichts <br>
§ 530        Verspätet vorgebrachte Angriffs- und Verteidigungsmittel <br>
§ 531        Zurückgewiesene und neue Angriffs- und Verteidigungsmittel <br>
§ 532        Rügen der Unzulässigkeit der Klage <br>
§ 533        Klageänderung ; Aufrechtserklärung; Widerlege <br>
§ 534        Verlust des Rügerechts <br>
§ 535        Gerichtliches Geständnis <br>
§ 536        Parteivernehmung <br>
§ 537        Vorläufige Vollstreckbarkeit <br>
§ 538        Zurückweisung <br>
§ 539        Versäumnisverfahren <br>
§ 540        Inhalt des Berufungsurteils <br>
§ 541        Prozessakten <br>
:::::::Abschnitt 2. Revision
§ 542        Standhaftigkeit der Revision <br>
§ 543        Zulassungsrevision <br>
§ 544        Nichtzulassungsbeschwerde <br>
§ 545        Revisionsgründe <br>
§ 546        Begriff der Rechtsverletzung <br>
§ 547        Absolute Revisionsgründe <br>
§ 548        Revisionsfrist <br>
§ 549        Revisionseinlegung <br>
§ 550        Zustellung der Revisionsschrift <br>
§ 551        Revisionsbegründung <br>
§ 552        Zulässigkeitsprüfung <br>
§ 552a      Zurückweisungsbeschluß <br>
§ 553        Terminbestimmung: Einlassungsfrist <br>
§ 554        Anschlußrevision <br>
§ 555        Allgemeine Verfahrensgrundsätze <br>
§ 556        Verlust des Rügerechts <br>
§ 557        Umfang der Revisionsprüfung <br>
§ 558        Vorläufige Vollstreckbarkeit <br>
§ 559        Beschränkte Nachprüfung tatsächlicher Feststellungen <br>
§ 560        Nicht reversible Gesetze <br>
§ 561        Revisionszurückweisung <br>
§ 562        Aufhebung des angefochtenen Urteils <br>
§ 563        Zurückverweisung; eigene Sachentscheidung<br>
§ 564        Keine Begründung der Entscheidung bei Rügen von Verfahrensmängeln <br>
§ 565        Anzuwendende Vorschriften des Berufungsverfahrens <br>
§ 566        Sprungrevision <br>
::::::::: Abschnitt 3. Beschwerde
:::::::: Titel 1. Sofortige Beschwerde
§ 567        Sofortige Beschwerde; Anschlussbeschwerde <br>
§ 568        Originärer Einzelrichter <br>
§ 569        Frist und Form <br>
§ 570        Aufschiebende Wirkung; einstweilige Anordnungen <br>
§ 571        Begründung, Präklusion, Ausnahmen vom Anwaltszwang <br>
§ 572        Gang des Beschwerdeverfahrens <br>
§ 573        Erinnerung <br>
:::::::: Titel 2. Rechtsbeschwerde
§ 574        Rechtsbeschwerde; Anschlussbeschwerde <br>
§ 575        Frist, Form und Begründung der Rechtsbeschwerde <br>
§ 576        Gründe der Rechtsbeschwerde <br>
§ 577        Prüfung und Entscheidung der Rechtsbeschwerde <br>
:::::::'''Buch 4. Wiederaufnahme des Verfahrens'''
§ 578        Arten der Wiederaufnahme <br>
§ 579        Nichtigkeitsklage <br>
§ 580        Restitutionsklage <br>
§ 581        Besondere Voraussetzungen der Restitutionsklage <br>
§ 582        Hilfsnatur der Restitutionsklage <br>
§ 583        Vorentscheidungen <br>
§ 584        Ausschließliche Zuständigkeit für Nichtigkeit- und Restitutionsklagen <br>
§ 585        Allgemeine Verfahrensgrundsätze <br>
§ 586        Klagefrist <br>
§ 587        Klageschrift <br>
§ 588        Inhalt der Klageschrift <br>
§ 589        Zulässigkeitsprüfung <br>
§ 590        Neue Verhandlung <br>
§ 591        Rechtsmittel <br>
:::::::'''Buch 5. Urkunden und Wechselprozess'''
§ 592        Zulässigkeit <br>
§ 593        Klageinhalt; Urkunden <br>
§ 594        (weggefallen) <br>
§ 595        Keine Widerklage; Beweismittel <br>
§ 596        Abstehen vom Urkundenprozess <br>
§ 597        Klageabweisung <br>
§ 598        Zurückweisung von Einwendungen <br>
§ 599        Vorbehaltsurteil <br>
§ 600        Nachverfahren <br>
§ 601        (weggefallen) <br>
§ 602        Wechselprozess <br>
§ 603        Gerichtsstand <br>
§ 604        Klageinhalt; Ladungsfrist <br>
§ 605        Beweisvorschriften <br>
§ 605a      Scheckprozess <br>
:::::::'''Buch 6. Musterfeststellungsverfahren'''
§ 606        Musterfeststellungsklage <br>
§ 607        Bekanntmachung der Musterfeststellungsklage <br>
§ 608        Anmeldung von Ansprüchen oder Rechtsverhältnissen <br>
§ 609        Klageregister; Verordnungsermächtigung <br>
§ 610        Besonderheiten der Musterfeststellungsklage <br>
§ 611        Vergleich <br>
§ 612        Bekanntmachungen zum Musterfeststellungsurteil <br>
§ 613        Bindungswirkung des Musterfeststellungsurteils; Aussetzung <br>
§ 614        Rechtsmittel <br>
§§ 615-687 (weggefallen) <br>
:::::::'''Buch 7. Mahnverfahren'''
§ 688        Zulässigkeit <br>
§ 689        Zuständigkeit; maschinelle Bearbeitung <br>
§ 690        Mahnantrag <br>
§ 691        Zurückweisung des Mahnantrags <br>
§ 692        Mahnbescheid <br>
§ 693        Zurückstellung des Mahnbescheids <br>
§ 694        Widerspruch gegen den Mahnbescheid <br>
§ 695        Mitteilung des Widerspruchs; Abschriften <br>
§ 696        Verfahren nach Widerspruch <br>
§ 697        Einleitung des Streitverfahrens <br>
§ 698        Abgabe des Vefahrens am selben Gericht <br>
§ 699        Vollstreckungsbescheid <br>
§ 700        Einspruch gegen den Vollstreckungsbescheid <br>
§ 701        Wegfall der Wirkung des Mahnbescheids <br>
§ 702        Form von Anträgen und Erkläriungen <br>
§ 703        Kein Nachweis der Vollmacht <br>
§ 703a      Urkunden Wechsel- und Scheckverfahren <br>
§ 703b      Sonderregelungen für maschinelle Bearbeitung <br>
§ 703c      Formulare; Einführung der maschinellen Bearbeitung <br>
§ 703d      Formulare; Antragsgegner ohne allgemeinen inländischen Gerichtsstand <br>
:::::::'''Buch 8. Zwangsvollstreckung'''
::::::::: Abschnitt 1. Allgemeine Vorschriften
§ 704        Vollstreckbare Endurteile <br>
§ 705        Formelle Rechtskraft <br>
§ 706        Rechtskraft- und Notfristzeugnis <br>
§ 707        Einstweilige Einstellung der Zwangsvollstreckung <br>
§ 708        Vorläufige Vollstreckbarkeit ohne Sicherheitsleistung <br>
§ 709        Vorläufige Vollstreckbarkeit gegen Sicherheitsleistung <br>
§ 710        Ausnahmen von der Sicherheitsleistung des Gläubigers <br>
§ 711        Abwendungsbefugnis <br>
§ 712        Schutzantrag des Schuldners <br>
§ 713        Unterbleiben von Schuldnerschutzanordnungen <br>
§ 714        Antrag zur vorläufigen Vollstreckbarkeit <br>
§ 715        Rückgabe der Sicherheits <br>
§ 716        Ergänzung des Urteils <br>
§ 717        Wirkungen eines aufhebenden oder abändernden Urteils <br>
§ 718        Vorentscheidung über vorläufige Vollstreckbarkeit <br>
§ 719        Einstweilig Einstellung bei Rechtsmittel und Einspruch <br>
§ 720        Hinterlegung bei Abwendung der Vollstreckung <br>
§ 720a      Sicherungsvollstreckung <br>
§ 721        Räumungsfrist <br>
§ 722        Vollstreckbarkeit ausländischer Urteile <br>
§ 723        Vollstreckungsurteil <br>
§ 724        Vollstreckbare Ausfertigung <br>
§ 725        Vollstreckungsklausel <br>
§ 726        Vollstreckbare Ausfertigung bei bedingten Leistungen <br>
§ 727        Vollstreckbare Ausfertigung für und gegen Rechtsnachfolger <br>
§ 728        Vollstreckbare Ausfertigung bei Nacherbe und Testamentsvollstrecker <br>
§ 729        Vollstreckbare Ausfertigung gegen Vermögens- und Firmenübernehmer <br>
§ 730        Anhörung des Schuldners <br>
§ 731        Klage auf Erteilung der Vollstreckungsklausel <br>
§ 732        Erinnerung gegen Erteilung der Vollstreckungsklausel <br>
§ 733        Weitere vollstreckbare Ausfertigung <br>
§ 734        Vermerk über Ausfertigungserteilung auf der Urteilsschrift <br>
§ 735        Hinterlegung bei Abwendung der Vollstreckung <br>
§ 736        Zwangsvollstreckung gegen BGB-Gesellschaft <br>
§ 737        Zwangsvollstreckung bei Vermögens- oder Erbschaftsnießbrauch <br>
§ 738        Vollstreckbare Ausfertigung gegen Nießbraucher <br>
§ 739        Gewahrsamsvermutung bei Zwangsvollstreckung gegen Ehepartner und Lebensgatten <br>
§ 740        Zwangsvollstreckung in das Gesamtgut <br>
§ 741        Zwangsvollstreckung in das Gesamtgut bei Erwerbsgeschäft <br>
§ 742        Vollstreckbare Ausfertigung bei Gütergemeinschaft während des Rechtsstreits <br>
§ 743        Beendete Gütergemeinschaft <br>
§ 744        Vollstreckbare Ausfertigung bei beendeter Gütergemeinschaft <br>
§ 744a      Zwangsvollstreckung bei Eigentums und Vermögensgemeinschaft <br>
§ 745        Zwangsvollstreckung bei fortgesetzter Gütergemeinschaft <br>
§ 746        (weggefallen) <br>
§ 747        Zwangsvollstreckung in ungeteilten Nachlass <br>
§ 748        Zwangsvollstreckung bei Testamentsvollstrecker <br>
§ 749        Vollstreckbare Ausfertigung für und gegen Testamentsvollstrecker <br>
§ 750        Voraussetzunge der Zwangsvollstreckung <br>
§ 751        Bedingungen für Vollstreckungsbeginn <br>
§ 752        Sicherheitsleistung bei Teilvollstreckung <br>
§ 753        Vollstreckung durch Gerichtsvollzieher; Verordnungsermächtigung <br>
§ 753a      Vollstreckungsnachweis <br>
§ 754        Vollstreckungsauftrag und vollstreckbare Ausfertigung <br>
§ 754a      Vereinfachter Vollstreckungsauftrag bei Vollstreckungsbescheiden <br>
§ 755        Ermittlung des Aufenthaltsorts des Schuldners <br>
§ 756        Zwangsvollstreckung bei Leistung Zug um Zug <br>
§ 757        Übergabe des Titels und Quittung <br>
'''''[ab 1.1.2022:]''''' <br>
§ 757a      Auskunft- und Unterstützungsersuchen <br>
§ 758        Durchsuchung; Gewaltanwendung <br>
§ 759        Zuziehung von Zeugen <br>
§ 760        Akteneinsicht; Aktenabschrift <br>
§ 761        (weggefallen) <br>
§ 762        Protokoll über Vollstreckungshandlungen <br>
§ 763        Aufforderungen und Mitteilungen <br>
§ 764        Vollstreckungsgericht <br>
§ 765        Vollstreckungsgerichtliche Anordnungen bei Leistung Zug um Zug <br>
§ 765a      Vollstreckungsschutz <br>
§ 766        Erinnerung gegen Art und Weise der Zwangsvollstreckung <br>
§ 767        Vollstreckungsabwehrklage <br>
§ 768        Klage gegen Vollstreckungsklausel <br>
§ 769        Einstweilige Anordnungen <br>
§ 770        Einstweilige Anordnungen im Urteil <br>
§ 771        Drittwiderspruchsklage <br>
§ 772        Drittwiderspruchsklage bei Veräußerungsverbot <br>
§ 773        Drittwiderspruchsklage des Nacherben <br>
§ 774        Drittwiderspruchsklage des Ehegatten oder Lebenspartners <br>
§ 775        Einstellung oder Beschränkung der Zwangsvollstreckung <br>
§ 776        Aufhebung von Vollstreckungsmaßregeln <br>
§ 777        Erinnerung bei genügender Sicherung des Gläubigers<br>
§ 778        Zwangsvollstreckung vor Erbschaftsannahme <br>
§ 779        Fortsetzung der Zwangsvollstreckung nach dem Tod des Schuldners <br>
§ 780        Vorbehalt der beschränkten Erbenhaftung <br>
§ 781        Beschränkte Erbenhaftung in der Zwangsvollstreckung <br>
§ 782        Einreden des Erben gegen Nachlassgläubiger <br>
§ 783        Einreden des Erben gegen persönliche Gläubiger <br>
§ 784        Zwangsvollstreckung bei Nachlassverwaltung und Insolvenzverfahren <br>
§ 785        Vollstreckungsabwehrklage des Erben <br>
§ 786        Vollstreckungsabwehrklage bei beschränkter Haftung <br>
§ 786a      See- und binnenschifffahrtsrechtliche Haftungsbeschränkung <br>
§ 787        Zwangsvollstreckung bei herrenlosem Grundstück oder Schiff <br>
§ 788        Kosten der Zwangsvollstreckung <br>
§ 789        Einschreiten von Behörden <br>
§ 790        (weggefallen) <br>
§ 791        (weggefallen) <br>
§ 792        Erteilung von Urkunden an Gläubiger <br>
§ 793        Sofortige Beschwerde <br>
§ 794        Weitere Vollstreckungstitel <br>
§ 794a      Zwangsvollstreckung aus Räumungsverkauf <br>
§ 795        Anwendung der allgemeinen Vorschriften auf die weiteren Vollstreckungstitel<br>
§ 795a      Zwangsvollstreckung aus Kostenfestsetzungsbeschluss <br>
§ 795b      Vollstreckbarerklärung des gerichtlichen Vergleichs <br>
§ 796        Zwangsvollstreckung aus Vollstreckungsbescheiden<br>
§ 796a      Voraussetzungen für die Vollstreckbarerklärung des Anwaltsvergleichs <br>
§ 797        Verfahren bei vollsteckbaren Urkunden<br>
§ 798        Wartefrist <br>
§ 798a      (weggefallen) <br>
§ 799        Vollstreckbare Urkunde bei Rechtsnachfolge <br>
§ 799a      Schadensersatzpflicht bei der Vollstrecking aus Urkunden durch andere Gläubiger <br>
§ 800        Vollstreckbare Urkunde gegen den jeweiligen Grundstückseigentümer <br>
§ 800a      Vollstreckbare Urkunde bei Schiffshypothek <br>
§ 801        Landesrechtliche Vollstreckungstitel <br>
§ 802        Auschließlichkeit der Gerichtsstände <br>
::::::::: Abschnitt 2. Zwangsvollstreckung wegen Geldforderungen
:::::::::::::Titel 1. Allgemeine Vorschriften
§ 802a      Grundsätze der Vollstreckung; Regelbefugnisse des Gerichtsvollziehers <br>
§ 802b      Gütliche Erledigung; Vollstreckungsaufschub bei Zahlungsvereinbarung <br>
§ 802c      Vermögensauskunft des Schuldners <br>
'''''[bis 31.12.2021:]''''' <br>
§ 802d      Erneute Vermögensauskunft <br>
'''''[ab 1.1.2022:]''''' <br>
§ 802e      Zuständigkeit <br>
§ 802f      Verfahren zur Abnahme der Vermögensauskunft <br>
§ 802g      Erzwingungshaft <br>
§ 802h      Unzulässigkeit der Haftvollstreckung <br>
§ 802i      Vermögensauskunft des verhafteten Schuldners <br>
§ 802j      Dauer der Haft; erneute Haft <br>
§ 802k      Zentrale Verwaltung der Vermögensverhzeichnisse <br>
§ 802l      Auskunftsrechte des Gerichtsvollziehers <br>
:::::::::::::Titel 2. Zwangsvollstreckung in das bewegliche Vermögen
:::::::::::::::::Untertitel 1. Allgemeine Vorschriften
§ 803        Pfändung <br>
§ 804        Pfändungspfandrecht <br>
§ 805        Klage auf Vorzugsweise Befriedigung <br>
§ 806        Keine Gewährleistung der Pfandveräusserung <br>
§ 806a      Mitteilungen und Befragung durch den Gerichtsvollzieher <br>
§ 807        Abnahme der Vermögensauskunft nach Pfandversuch <br>
:::::::::::::Untertitel 2. Zwangsvollstreckung in körperliche Sachen
§ 808        Pfändung beim Schuldner <br>
§ 809        Pfändung beim Gläubiger oder bei Dritten <br>
§ 810        Pfändung ungetrennter Früchte <br>
'''''[ab 31.12.2021:]''''' <br>
§ 811        Unpfändbare Sachen <br>
'''''[ab 1.1.2022:]''''' <br>
§ 811        ''Unpfändbare Sachen und Tiere ''<br>
§ 811a      Austauschpfändung<br>
§ 811b      Vorläufige Austauschpfändung<br>
'''''[ab 31.12.2021:]''''' <br>
§ 811c      Unpfändbarkeit von Haustieren<br>
§ 811d      Vorwegpfändung<br>
§ 812        Pfändung von Hausrat<br>
§ 813        Schätzung<br>
§ 814        Öffentliche Versteigerung<br>
§ 815        Gepfändetes Geld<br>
§ 816        Zeit und Ort der Versteigerung<br>
§ 817        Zuschlag und Ablieferung<br>
§ 817a      Mindestgebot<br>
§ 818        Einstellung der Versteigerungt<br>
§ 819        Wirkung des Erlösempfängers<br>
§ 820        (weggefallen)<br>
§ 821        Verwertung von Werkpapieren<br>
§ 822        Umschreibung von Namenspapieren<br>
§ 823        Außer Kurs gesetzte Inhaberpapiere<br>
§ 824        Pfändung von Hausrat<br>
§ 825        Andere Verwertungsart<br>
§ 826        Anschlussprüfung<br>
§ 827        Verfahren bei mehrfacher Pfändung<br>
:Untertitel 3. Zwangsvollstreckung in Forderungen und anderen Vermögensrechte
§ 828        Zuständigkeit des Vollstreckungsgerichts<br>
§ 829        Pfändung einer Geldforderung<br>
§ 830        Pfändung einer Hypothekenforderung<br>
§ 831        Pfändung indossabler Papiere<br>
§ 832        Pfändungsumfang bei fortlaufenden Bezügen<br>
§ 833        Pfändungsumfang bei Arbeits- oder Diensteinkommen<br>
§ 833a      Pfändungsumfang bei Kontoguthaben<br>
§ 834        Keine Anhörung des Schuldners<br>
§ 835        Überweisung einer Geldforderung<br>
§ 836        Wirkung der Überweisung<br>
§ 837        Überweisung einer Hypothekenforderung<br>
§ 837a      Überweisung einer Schiffshypothekenforderung<br>
§ 838        Einrede des Schuldners bei Faustpfand<br>
§ 839        Überweisung bei Anwendungsbefugnis<br>
§ 840        Erklärungspflicht des Drittschuldners<br>
§ 841        Pflicht zur Streitverkündungs<br>
§ 842        Schadensersatz bei verzögerter Beitreibung<br>
§ 843        Verzicht des Pfandgläubigers<br>
§ 844        Andere Verwendungen<br>
§ 845        Vorpfändung<br>
§ 846        Zwangsvollstreckung in Herausgabeansprüche<br>
§ 847        Herausgabeanspruch auf eine bewegliche Sache<br>
§ 848        Herausgabeanspruch auf eine unbewegliche Sache<br>
§ 849        Keine Überweisung an Zahlungs statt<br>
§ 850        Pfändungsschutz für Arbeitseinkommen<br>
§ 850a      Unpfändbare Bezüge<br>
§ 850b      Bedingt pfändbare Bezüge<br>
§ 850c      Pfändungsgrenzen für Arbeitseinkommen<br>
§ 850d      Pfändbarkeit bei Unterhaltsansprüchen<br>
§ 850e      Berechnung des pfändbaren Arbeitseinkommen<br>
§ 850f       Änderung des unpfändbare Betrages<br>
§ 850g      Änderung der Unpfändbarkeitsvoraussetzungen<br>
§ 850h      Verschleiertes Arbeitseinkommen<br>
§ 850i       Pfändungsschutz für sonstige Einkünfte<br>
'''''[ab 30.11.2021:]''''' <br>
§ 850k       Pfändungsschutzkonto<br>
§ 850l       Anordnung der Unpfändbarkeit von Kontoguthaben auf dem Pfändungsschutzkonto<br>
'''''[ab 01.12.2021:]''''' <br>
§ ''850k''       ''Einrichtung und Beendigung des Pfandschutzkontos''<br>
§ ''850l''       ''Pfändung des Gemeinschaftskontos''<br>
§ 851        Nicht übertragbare Forderungen<br>
§ 851a       Pfändungsschutz für Landwirte<br>
§ 851b       Pfändungsschutz bei Miet- und Pachtzinsen<br>
§ 851c       Pfändungsschutz bei Altersrenten<br>
§ 851d       Pfändungsschutz bei steuerlich gefördertem Altersvorsorgevermögen<br>
§ 852        Beschränkt pfändbare Forderungen<br>
§ 853        Mehrfache Pfändung einer Geldforderung<br>
§ 854        Mehrfache Pfändung eines Anspruchs auf bewegliche Sachen<br>
§ 855        Mehrfache Pfändung eines Anspruchs auf unbewegliche Sachen<br>
§ 855a      Mehrfache Pfändung eines Anspruchs auf ein Schiff<br>
§ 856        Klage bei mehrfacher Pfändung<br>
§ 857        Zwangsvollstreckung in andere Vermögensrechte<br>
§ 858        Zwangsvollstreckung in Schiffspart<br>
§ 859        Pfändung von Gesamthandanteilen<br>
§ 860        Pfändung von Gesamtgutanteilen<br>
§§ 861, 862 (weggefallen)<br>
§ 863        Pfändungsbeschränkungen bei Erbschaftsnutzungen<br>
:::::::::::::Titel 3. Zwangsvollstreckung in das unbewegliche Vermögen<br>
§ 864        Gegenstand der Immobiliarvollstreckung<br>
§ 865        Verhältnis zur Mobiliarvollstreckung<br>
§ 866        Arten der Vollstreckung<br>
§ 867        Zwangshypothek<br>
§ 868        Erwerb der Zwangshypothek durch den Eigentümer<br>
§ 869        Erwerb der Zwangsversteigerung und Zwangsverwaltung<br>
§ 870        Grundstücksgleiche Rechte<br>
§ 870a      Zwangsvollstreckung in ein Schiff oder Schiffsbauwerk<br>
§ 871        Landesrechtlicher Vorbehalt bei Eisenbahnen<br>
:::::::::::::Titel 4. Verteilungsverfahren
§ 872        Voraussetzungen<br>
§ 873        Aufforderung des Verteilungsgerichts<br>
§ 874        Teilungsplan<br>
§ 875        Terminsbestimmung<br>
§ 876        Termin zur Erklärung und Ausführung<br>
§ 877        Säumnisfolgen<br>
§ 878        Widerspruchsklage<br>
§ 879        Zuständigkeit für die Widerspruchsklage<br>
§ 880        Inhalt des Urteils<br>
§ 881        Versäumnisurteil<br>
§ 882        Verfahren nach dem Urteil<br>
::::::Titel 5. ''[bis 30.11.2021: Zwangsvollstreckung gegen juristische Personen des öffentlichen Rechts''']<br>
:::::[ab 1.12.20211: Zwangsvollstreckung in Sachen, die der Erfüllung öffentlicher Aufgaben dienen]
§ 882a       Zwangsvollstreckung wegen einer Geldforderung<br>
:::::::::::::Titel 6. Schuldnerverzeichnbis
§ 882b       Inhalt des Schuldnerverzeichnisses<br>
§ 882c       Eintragungsanordnung<br>
§ 882d       Vollziehung der Eintragungsanordnung<br>
§ 882e       Löschung<br>
§ 882f       Einsicht in das Schuldnerverzeichnis<br>
§ 882g       Erteilung von Abdrucken<br>
§ 882h       Zuständigkeit; Ausgestaltung des Schuldnerverzeichnisses<br>
§ 882i       Rechte der Betroffenen<br>
Abschnitt 3. Zwangsvollstreckung zur Erwirkung der Herausgabe von Sachen und zur Erwirkung von<br>
::::::::::::Handlungen oder Unterlassungen
§ 883        Herausgabe bestimmter beweglicher Sachen<br>
§ 884        Leistung einer bestimmten Menge vertretbarer Sachen<br>
§ 885        Herausgabe von Grundstücken oder Schiffen<br>
§ 886        Herausgabe bei Gewahrsam eines Dritten<br>
§ 887        Vertretbare Handlungen<br>
§ 888        Nicht vertretbare Handlungen<br>
§ 888a      Keine Handlungsvollstreckung bei Entschädigungspflicht<br>
§ 889        Eidesstattliche Versicherung nach bürgerlichem Recht<br>
§ 890        Erzwingung von Unterlassungen und Duldungen<br>
§ 891        Verfahren; Anhörung des Schuldners; Kostenentscheidung<br>
§ 892        Widerstand des Schuldners<br>
§ 893        Klage auf Leistung des Interesses<br>
§ 894        Fiktion der Abgabe einer Willenserklärung<br>
§ 895        Willenserklärung zwecks Eintragung bei vorläufig vollstreckbarem Urteil<br>
§ 896        Erteilung von Urkunden an Gläubiger<br>
§ 897        Übereignung; Verschiffung von Grundpfandrechten<br>
§ 898        Gutgläubiger Erwerb<br>
'''''[bis 30.11.2021:]''''' <br>
§§ 899 - 915h (aufgehoben)
'''''[ab 1.12.2021:]''''' <br>
::::::::: Abschnitt 4. Wirkungen des Pfändungsschutzkontos
§ 899        Pfändungsfreier Betrag; Übertragung<br>
§ 900        Moratorium bei Überweisung an den Gläubiger<br>
§ 901        Verbot der Aufrechnung und Verrechnung<br>
§ 902        Erhöhungsbeträge<br>
§ 903        Nachweise über Erhöhungsbeträge<br>
§ 904        Nachzahlung von Leistungen<br>
§ 905        Festsetzung der Erhöhungsbeträge durch das Vollstreckungsgericht<br>
§ 906        Festsetzung eines abweichenden pfändungsfreien Betrages durch das Vollstreckungsgericht<br>
§ 907        Festsetzung der Unpfändbarkeit von Kontoguthaben auf dem Pfändungskonto<br>
§ 908        Aufgaben des Kreditinstituts<br>
§ 909        Datenweitergabe; Löschungspflicht<br>
§ 910        Verwaltungsvollsteckung<br>
§. 911 bis 915h (weggefallen)<br>
::::::::: Abschnitt 5. Arrest und einstweilige Verfügung<br>
§ 916        Arrestanspruch<br>
§ 917        Arrestgrund bei dinglichem Arrest<br>
§ 918        Arrestgrund bei persönlichem Arrest<br>
§ 919        Arrestgericht<br>
§ 920        Arrestgesuch<br>
§ 921        Entscheidung über das Arrestgesuch<br>
§ 922        Arresturteil und Arrestbeschluss<br>
§ 923        Anwendungsbefugnis<br>
§ 924        Widerspruch<br>
§ 925        Entscheidung nach Widerspruch<br>
§ 926        Anordnung der Klageerhebung<br>
§ 927        Aufhebung wegen veränderter Umstände<br>
§ 928        Vollziehung des Arrestes<br>
§ 929        Vollstrechungsklausel; Vollziehungsfrist<br>
§ 930        Vollziehung in bewegliches Vermögen und Forderungen<br>
§ 931        Vollziehung in eingetragenes Schiff oder Schiffsbauwerk<br>
§ 932        Arresthypothek<br>
§ 933        Vollziehung des persönlichen Arrestes<br>
§ 934        Aufhebung der Arrestvollziehung<br>
§ 935        Einstweilige Verfügung bezüglich Streitgegenstand<br>
§ 936        Anwendung der Arrestvorschriften<br>
§ 937        Zuständiges Gericht<br>
§ 938        Inhalt der Einstweiligen Verfügung<br>
§ 939        Aufhebung gegen Sicherheitsleistung<br>
§ 940        Einstweilige Verfügung zur Regelung eines weiteren Zustandes<br>
§ 940a      Räumung von Wohnraum<br>
§ 941        Ersuchen um Eintragungen ins Grundbuch usw.<br>
§ 942        Zuständigkeit des Amtsgerichts der belegenen Sache<br>
§ 943        Gericht der Hauptsache<br>
§ 944        Entscheidung des Vorsitzenden bei Dringlichkeit<br>
§ 945        Schadensersatzprlicht<br>
§ 945a      Einreichung von Schutzvorschriften<br>
§ 945b      Verordnungsermächtigung<br>
::::::::: Abschnitt 6. Grenzüberschreitende vorläufige Kontenpfändung<br>
::::::::: Titel 1. Erlass des Beschlusses zur vorläufigen Kontenpfändung<br>
§ 946        Zuständigkeit<br>
§ 947        Verfahren<br>
§ 948        Ersuchen um Einholen von Konteninformationen<br>
§ 949        Nicht rechtzeitige Einleitung des Hauptverfahrens<br>
::::::::: Titel 2. Vollziehung des Beschlusses zur vorläufigen Kontenpfändung<br>
§ 950        Anwendbare Vorschriften<br>
§ 951        Vollziehung von im Inland erlassenen Beschlüssen<br>
§ 952        Vollziehung von einem anderen Mitgliedstaat erlassenen Beschlüssen<br>
::::::::: Titel 3. Rechtsbehelfe
§ 953        Rechtsbehelfe des Gläubigers<br>
§ 954        Rechtsbehelfe nach den Artikeln 33 bis 35 der Verordnung (EU) Nr. 655/2014<br>
§ 955        Sicherheitsleistung nach Artikel 38 der Verordnung (EU) Nr. 655/2014<br>
§ 956        Rechtsmittel gegen die Entscheidungen nach § 954 Absatz 1 bis 3 und § 955<br>
§ 957        Ausschluss der Rechtsbeschwerde<br>
::::::::: Titel 4. Schadensersatz, Verordnungsermächtigung
§ 958        Schadensersatz<br>
§ 959        Verordnungsermächtigung<br>
:::::::::::: '''Buch 9.''' (weggefallen)
§§ 960 - 1024        (aufgehoben)<br>
::::::::: '''Buch 10. Schiedsrichterliches Verfahren '''
:::::::::: Abschnitt 1. Allgemeine Vorschriften
§ 1025        Anwendungsbereich<br>
§ 1026        Umfang gerichtlicher Tätigkeit<br>
§ 1027        Verlust des Rügerechts<br>
§ 1028        Empfang schriftlicher Mitteilungen bei unbekanntem Aufenthalt<br>
:::::::::: Abschnitt 2. Schiedsvereinbarung
§ 1029        Begriffsbestimmung<br>
= § 1 (ZPO) Sachliche Zuständigkeit. =
Die sachliche Zuständigkeit der Gerichte wird durch das Gesetz über die Gerichtsverfassung 2) bestimmt. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 2 (ZPO) Bedeutung des Wertes. =
Kommt es nach den Vorschriften dieses Gesetztes oder des Gerichtsverfassungsgesetzes 2) auf den Wert des Streitgegenstandes des Beschwerdegegenstandes, der Beschwerde oder der Verurteilung an, so gelten die nachfolgenden Vorschriften. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 3 (ZPO) Wertfestsetzung nach freiem Ermessen. =
Der Wert wird von dem Gericht nach freiem Ermessen festgesetzt; es kann eine beantragte Beweisaufnahme sowie von Amts wegen die Einnahme des Augenscheins und die Begutachtung durch Sachverständige anordnen. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 4 (ZPO) Wertberechnung: Nebenforderungen. =
(1) Für die Wertberechnung 3) ist der Zeitpunkt der Einreichung der Klage, in der Rechtsmittelinstanz der Zeitpunkt der Einlegung des Rechtsmittels, bei der Verurteilung der Zeitpunkt des Schlusses der mündlichen Verhandlung, auf die das Urteil ergeht, entscheidend; Früchte, Nutzungen, Zinsen und Kosten bleiben unberücksichtigt, wenn sie als Nebenforderungen geltend gemacht werden. (2) Bei Ansprüchen aus Wechseln im Sinne des Wechselgesetzes sind Zinsen, Kosten und Provision, die außer der Wechselsumme gefordert werden, als Nebenforderungen anzusehen. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 5 (ZPO) Mehrere Ansprüche. =
Mehrere in einer Klage geltend gemachte Ansprüche werden zusammengerechnet; dies gilt nicht für den Gegenstand der Klage und der Widerklage. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 6 (ZPO) Besitz; Sicherstellung; Pfandrecht. =
<sup>1</sup> Der Wert wird bestimmt; durch den Wert einer Sache; wenn es auf deren Besitz und durch den Betrag einer Forderung, wenn es auf deren Sicherstellung oder ein Pfandrecht ankommt.<sup>2</sup> Hat der Gegenstand des Pfandrechts einen geringeren Wert, so ist dieser maßgebend. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 7 (ZPO) Grunddienstbarkeit. =
Der Wert einer Grunddienstbarkeit wird durch den Wert, den sie für das herrschende Grundstück hat, und wenn der Betrag, um den sich der Wert des dienenden Grundstücks durch die Dienstbarkeit mindert, größer ist, durch diesen Betrag bestimmt. '''(Quellinfo = Buch "ZPO" S. 22 ff.)'''
= § 8 (ZPO) <sup> 1) </sup> Pacht- oder Mietverhältnis. =
Ist das Bestehen oder die Dauer eines Pacht- oder Mietverhältnisses streitig, so ist der Betrag der auf die gesamte streitige Zeit entfallenden Pacht oder Miete und, wenn der 25fache Betrag des einjährigen Entgelts geringer ist, dieser Betrag für die Wertberechnung entscheidend. '''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 9 (ZPO) <sup> 2) </sup> Wiederkehrende Nutzungen oder Leistungen. =
1 Der Wert des Rechts auf wiederkehrende Nutzungen oder Leistungen wird nach dem dreieinhalbfachen Wert des einjährigen Bezuges berechnet. 2 Bei bestimmter Dauer des Bezugsrechts ist der Gesamtbetrag der künftigen Bezüge maßgebend, wenn er der geringere ist. '''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 10 (ZPO) (weggefallen) =
'''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 11 (ZPO) Bindende Entscheidung über Unzuständigkeit =
Ist die Unzuständigkeit eines Gerichts auf Grund der Vorschriften über die sachliche Zuständigkeit der Gerichte rechtskräftig ausgesprochen, so ist diese Entscheidung für das Gericht bindend, bei dem die Sache später anhängig wird. '''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
:::'''Titel 2. Gerichtsstand'''
= § 12³) (ZPO) Allgemeiner Gerichtsstand; Begriff. =
Das Gericht, bei dem eine Person ihren allgemeinen Gerichtsstand hat, ist für alle gegen sie zu erhebenden Klagen zuständig, sofern nicht für eine klage ein ausschließlicher Gerichtsstand begründet ist. '''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 13) (ZPO) Allgemeiner Gerichtsstand des Wohnsitzes. =
Der allgemeine Gerichtsstand einer Person wird durch den Wohnsitz bestimmt '''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 14) (ZPO) (weggefallen) =
'''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 15 (ZPO) Allgemeiner Gerichtsstand für exterritoriale Deutsche =
(1)<sup>1</sup> Deutsche, die das Recht der Exterritorialität genießen, sowie die im Ausland beschäftigten deutschen Angehörigen des öffentlichen Diensts behalten den Gerichtsstand ihres letzten inländischen Wohnsitzes. <sup>2</sup> Wenn sie einen solchen Wohnsitz nicht hatten, habe sie ihren allgemeinen Gerichtsstand beim Amtsgericht Schöneberg in Berlin. (2) Auf Honorarkonsuln ist diese Vorschrift nicht anzuwenden.
'''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 16 (ZPO) Allgemeiner Gerichtsstand wohnsitzloser Personen =
Der allgemeine Gerichtstand einer Person, die keinen Wohnsitz hat, wird durch den Aufenthaltsort im Inland und, wenn ein solcher nicht bekannt ist, durch den letzten Wohnsitz bestimmt. '''(Quellinfo = Buch "ZPO" S. 23 ff.)'''
= § 17 (ZPO) Allgemeiner Gerichtsstand juristischer Personen =
(1) <sup> 1 </sup> Der allgemeine Gerichtsstand der Gemeinden, der Korporationen sowie derjenigen Gesellschaften, Genossenschaften oder anderen Vereine und derjenigen Stiftungen, Anstalten und Vermögensmassen, die als solche verklagt werden können, wird durch ihren Sitz bestimmt. <sup> 2 </sup> Als Sitz gilt, wenn sich nichts anderes ergibt, der Ort, wo die Verwaltung geführt wird. (2) Gewerkschaften haben den allgemeinen Gerichtstand bei dem Gericht, in dessen Bezirk das Bergwerk liegt, Behörden, wenn sie als solche verklagt werden können, bei dem Gericht ihres Amtssitzes. (3) Neben dem durch die Vorschriften dieses Paragraphen bestimmten Gerichtsstand ist ein durch Statut oder in anderer Weise besonders geregelter Gerichtsstand zulässig. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''
= § 18 Allgemeiner Gerichtsstand des Fiskus =
Der allgemeine Gerichtsstand des Fiskus wird durch den Sitz der Behörde bestimmt, die berufen ist, den Fiskus in dem Rechtsstreit zu vertreten. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''
= § 19 Mehrere Gerichtsbezirke am Behördensitz =
Ist der Ort, an dem eine Behörde ihren Sitz hat, in mehrere Gerichtsbezirke geteilt, so wird der Bezirk der im Sinne der §§ 17, 18 als Sitz der Behörde gilt, für die Bundesbehörden von dem Bundesministerium der Justiz und für Verbraucherschutz, im Übrigen von der Landesjustizverwaltung durch allgemeine Anordnung bestimmt. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''
= § 19 <sub> a </sub> Allgemeiner Gerichtsstand des Insolvenzverwalters. =
Der allgemeine Gerichtsstand eines Isolvenzverwalters für Klagen, die sich auf die Insolvenzmasse beziehen, wird durch den Sitz des Insolvenzgerichts bestimmt. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''
= § 19 <sub> b </sub> Allgemeiner Gerichtsstand bei restrukturierungsbezogene Klagen; Verordnungsermächtigung. =
(1) Für Klagen, die sich auf Restrukturierungssachen nach dem Unternehmensstabilisierungs- und -retrukturierungsgesetz beziehen, ist ausschließlich das Gericht zuständig, in dessen Bezirk das für die Restrukturierungssache zuständige Restrukturierungsgericht seinen Sitz hat.
<div style="text-indent: 38px;"> (2) <sup> 1 </sup>Die Landesregierungen werden ermächtigt, durch Rechtsverordnung die in Absatz 1 genannten Klagen einem Landgericht für die Bezirke mehrerer Oberlandesgerichte zuzuweisen, sofern dies der sachlichen Förderung oder schnelleren Erledigung der Verfahren dienlich ist. <sup>2</sup>Die Landesregierungen können die Ermächtigung durch Rechtsverordnung auf die Landesjustizverwaltungen übertragen. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''</div>
= § 20 Besonderer Gerichtsstand des Aufenthaltsorts. =
Wenn Personen an einem Ort unter Verhältnissen, die ihrer Natur nach auf einen Aufenthalt von längerer Dauer hinweisen, insbesondere als Hausgehilfen, Arbeiter, Gewerbehilfen, Studierende, Schüler oder Lehrlinge sich aufhalten, so ist das Gericht des Aufenthaltsortes für alle Klagen zuständig, die gegen dieser Personen wegen vermögensrechtlicher Ansprüche erhoben werden. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''
= § 21 Besonderer Gerichtsstand der Niederlassung. =
(1) hat jemand zum Betrieb einer Fabrik, einer Handlung oder eines anderen Gewerbes eine Niederlassung, von der aus unmittelbar Geschäfte geschlossen werden, so können gegen ihn alle Klagen, die auf den Geschäftsbetrieb der Niederlassung Bezug haben, bei dem Gericht des Ortes erhoben werden, wo die Niederlassung sich befindet. '''(Quellinfo = Buch "ZPO" S. 24 ff.)'''
= § 22 Besonderer Gerichtsstand der Mitgliedschaft. =
Das Gericht, bei dem Gemeinden, Korporationen, Gesellschaften, Genossenschaften oder andere Vereine den allgemeinen Gerichtsstand haben, ist für die Klagen zuständig, die von ihnen oder von dem Insolvenzverwalter gegen die Mitglieder als solche oder von den Mitgliedern in dieser Eigenschaft gegeneinander erhoben werden. '''(Quellinfo = Buch "ZPO" S. 25 ff.)'''
= § 23<sup>1)</sup>Besonderer Gerichtsstand des Vermögens und des Gegenstands. =
<sup>1</sup> Für Klagen wegen vermögensrechtlicher Ansprüche gegen eine Person, die im Inland keinen Wohnsitz hat, ist das Gericht zuständig, in dessen Bezirk sich Vermögen derselben oder der mit der Klage in Anspruch genommene Gegenstand befindet. <sup>2</sup> Bei Forderungen gilt als der Ort, wo das Vermögen sich befindet, der Wohnsitz des Schuldners und, wenn für die Forderungen eine Sache zur Sicherheit haftet, auch der Ort, wo die Sache sich befindet. '''(Quellinfo = Buch "ZPO" S. 25 ff.)'''
= § 23a (aufgehoben) =
= § 24 Ausschließlicher dinglicher Gerichtsstand. =
(1) Für Klagen, durch die das Eigentum, eine dingliche Belastung oder die Freiheit von einer solchen geltend gemacht wird, für Grenzscheidungs-, Teilung- und Besitzklagen ist, sofern es sich um unbewegliche Sachen handelt, das Gericht ausschließlich zuständig, in dessen Bezirk die Sache belegen ist. (2) Bei den eine Grunddienstbarkeit, eine Reallast oder ein Vorkaufsrecht betreffenden Klagen ist die Lage des dienenden oder belasteten Grundstücks entscheidend. '''(Quellinfo = Buch "ZPO" S. 25 ff.)'''
= § 25 Dinglicher Gerichtsstand des Sachzusammenhanges. =
In dem dinglichen Gerichtsstand kann mit der Klage aus einer Hypothek, Grundschuld oder Rentenschuld die Schuldklage, mit der Klage auf Umschreibung oder Löschung einer Hypothek, Grundschuld oder Rentenschuld die Klage auf Befreiung von der persönlichen Verbindlichkekt mit der Klage auf Anerkennung einer Reallast die Klage auf rückständige Leistungen erhoben werden, wenn die verbundenen Klagen gegen denselben Beklagten gerichtet sind. '''(Quellinfo = Buch "ZPO" S. 25 ff.)'''
= § 26 Dinglicher Gerichtsstand für persönliche Klagen. =
In dem dinglichen Gerichtsstand können persönliche Klagen, die gegen die Eigentümer oder Besitzer einer unbeweglichen Sache als solche gerichtet werden, sowie Klagen wegen Beschädigung eines Grundstücks oder hinsichtlich der Entschädigung wegen Enteignung eines Grundstücks erhoben werden. '''(Quellinfo = Buch "ZPO" S. 25 ff.)'''
= § 27 Besonderer Gerichtsstand der Erbschaft. =
(1) Kagen, welche die Feststellung des Erbrechts, Ansprüche des Erben gegen einen Erbschaftsbesitzer, Anprüche aus Vermächtnissen oder sonstigen Verfügungen von Todes wegen, Pflichtteilsansprüche oder die Teilung der Erbschaft zum Gegenstand haben, können vor dem Gericht erhoben werden, bei dem er Erblasser zur zeit seines Todes den allgemeinen Gerichtsstand gehabt hat. (2) Ist der Erblasser ein Deutscher und hatte er zur Zeit seines Todes im Inland keinen allgemeinen Gerichtsstand, so können die im Absatz 1 bezeichneten Klagen vor dem Gericht erhoben werden, in dessen Bezirk der Erblasser seinen letzten inländischen Wohnsitz hatte, wenn er einen solchen Wohnsitz nicht hatte, so gilt die Vorschrift des § 15 Abs., 1 Satz 2 entsprechend. '''(Quellinfo = Buch "ZPO" S. 26 ff.)'''
= § 28 Erweiterter Gerichtsstand der Erbschaft. =
In dem Gerichtsstand der Erbschaft können auch Klagen wegen anderer Nachlassverbindlichkeiten erhoben werden, solange sich der Nachlass noch ganz oder teilweise im Bezirk des Gerichts befindet oder die vorhandenen mehreren Erben noch als Gesamtschuldner haften. '''(Quellinfo = Buch "ZPO" S. 26 ff.)'''
= § 29 Besonderer Gerichtsstand des Erfüllungsorts. =
(1) Für Streitigkeiten aus einem Ertragsverhältnis und über deren Betehen ist das Gericht des Ortes zuständig, an dem die streitige Verpflichtung zu erfüllen ist. (2) Eine Vereinbarung über den Erfüllungsort begründet die Zuständigkeit nur, wenn die Vertragsparteien Kaufleute, juristische Personen des öffentlichen Rechts oder öffentlich-rechtliche Sondervermögen sind. '''(Quellinfo = Buch "ZPO" S. 26 ff.)'''
= § 29a Ausschließlicher Gerichtstand bei Miet- oder Pachträumen. =
(1) Für Streitigkeiten über Ansprüche aus Miet- oder Pachtverhältnissen über Räume oder über dessen Bestehen solcher Verhältnisse ist das Gericht ausschließlich zuständig, in dessen Bezirk sich die Räume befinden. (2) Absatz 1 ist nicht anzuwenden, wenn es sich um Wohnraum der in § 549 Abs. 2 Nr. 1 bis 3 des Bürgerlichen Gesetzbuchs genannten Art handelt. '''(Quellinfo = Buch "ZPO" S. 26 ff.)'''
= § 29b (aufgehoben) =
= § 29c Besonderer Gerichtsstand für Haustürgeschäfte. =
(1)<sup>1</sup>Für Klagen aus außerhalb von Geschäftsräumen geschlossenen Verträgen (§312b des Bürgerlichen Gesetzbuchs) ist das Gericht zuständig, in dessen Bezirk der Verbraucher zur Zeit der Klageerhebung seinen Wohnsitz, in Ermangelung eines solchen seinen gewöhnlichen Aufenthalt hat. <sup>2</sup> Für Klagen gegen den Verbraucher ist dieses Gericht ausschließlich zuständig. (2) Verbraucher ist jede natürliche Person, die bei dem Erwerb des Anspruchs oder der Begründung des Rechtsverhältnisses nicht überwiegend im Rahmen ihrer gewerblichen oder selbständigen beruflichen Tätigkeit handelt. (3) § 33 Abs. 2 findet auf Widerklagen der anderen Vertragspartei keine Anwendung. (4) Eine von Absatz 1 abweichende Vereinbarung ist zulässig für den Fall, dass der Verbraucher nach Vertragsschluss seinen Wohnsitz oder gewöhnlicher Aufenthalt im Zeitpunkt der Klageerhebung nicht bekannt ist.
'''(Quellinfo = Buch "ZPO" S. 26 ff.)'''
= § 30 Gerichtsstand bei Beförderungen. =
(1)<sup>1</sup>Für Rechtsstreitigkeiten aus einer Güterbeförderung ist auch das Gericht zuständig, in dessen Bezirk der Ort der Übernahme des Gutes oder der für die Ablieferung des Gutes vorgegebene Ort liegt. <sup>2</sup>Eine Klage gegen den ausführenden Frachtführer oder ausführenden Verfrachter kann auch in dem Gerichtstand des Frachtführers oder Verfrachtete erhoben werden. <sup>3</sup> Eine Klage gegen den Frachtführer oder ausführenden Verfrachter kann auch in dem Gerichtsstand des ausführenden Frachtführers oder ausführenden Verfrachtete erhoben werden. (2)<sup>1</sup> Für Rechtsstreitigkeiten wegen einer Beförderung von Fahrgästen und ihrem Gepäck auf Schiffen ist auch das Gericht zuständig, in dessen Bezirk sich der im Beförderungsvertrag bestimmte Abgangs- oder Bestimmungsort befindet. <sup>2</sup>Eine von Satz 1 abweichende Vereinbarung ist unwirksam, wenn sie vor Eintritt des Ereignisses getroffen wird, das den Tod oder die Körperverletzung des Fahrgasts oder den Verlust, die Beschädigung oder die verspätete Aushändigung des Gepäcks verursacht hat.'''(Quellinfo = Buch "ZPO" S. 26 ff.)'''
= § 30a Gerichtsstand bei Bergungsansprüchen. =
Für Klagen wegen Ansprüchen aus Bergung von Schiffen oder sonstigen Vermögensgegenständen in einem Gewässer gegen eine Person, die im Inland keinen Gerichtsstand hat, ist das Gericht zuständig, bei dem der Kläger im Inland seinen allgemeinen Gerichtstand hat. '''(Quellinfo = Buch "ZPO" S. 27 ff.)'''
= § 31 Besonderer Gerichtstand der Vermögensverwaltung. =
Für Klagen, die aus einer Vermögensverwaltung von dem Geschäftsherrn gegen den Verwalter oder von dem Verwalter gegen den Geschätsherrn erhoben werden, ist das Gericht des Ortes zuständig, wo die Verwaltung geführt ist. '''(Quellinfo = Buch "ZPO" S. 276 ff.)'''
= § 32 Besonderer Gerichtsstand der unerlaubten Handlung. =
Für Klagen aus unerlaubten Handlungen ist das Gericht zuständig, in dessen Bezirk die Handlung begangen ist. '''(Quellinfo = Buch "ZPO" S. 27 ff.)'''
= § 32a Ausschließlicher Gerichtsstand der Umwelteinwirkung. =
<sup>1</sup>Für Klagen gegen den Inhaber einer im Anhang 1 des Umwelthaftungsgesetzes genannten Anlage, mit denen der Ersatz eines durch eine Umwelteinwirkungverursachten Schadens geltend gemacht wird, ist das Gericht ausschließlich zuständig, in dessen Bezirk die Umwelteinwirkung von der Anlage ausgegangen ist. <sup>2</sup>Dies gilt nicht, wenn die Anlage im Ausland belegen ist.
= § 32b<sup>1)</sup> Ausschließlicher Gerichtsstand bei falschen, irreführenden oder unterlassenen öffentlichen Kapitalmarktinformationen. =
(1) Für Klagen, in denen 1. ein Schadensersatzanspruch wegen falscher, irreführender oder unterlassener öffentlicher Kapitalmarktinformation, 2. ein Schadensersatzanpruch wegen Verwendung einer falschen oder irreführenden öffentlichen Kapitalmarktinformation oder wegen Unterlassung der gebotenen Aufklärung darüber das eine öffentliche Kapitalmarktinformation falsch oder irreführend ist, oder 3. ein Erfüllunganspruch aus Vertrag, der auf einem Angebot nach dem Wertpapiererwerbs- und Übernahmegesetz beruht, geltend gemacht wird, ist das Gericht ausschließlich am Sitz des betroffenen Emittenten, des betroffenen Anbieters von sonstigen Vermögensanlagen oder der Zielgesellschaft zuständig, wenn sich dieser Sitz im Inland befindend und die Klage zumindest auch gegen den Emittenten, den Anbieter oder die Zielgesellschaft gerichtet wird. (2)<sup>1</sup> Die Landesregierungen werden ermächtigt, durch Rechtsverordnung, die im Absatz 1 genannten Klagen einem Landgericht für die Bezirke mehrerer Landgerichte zuzuweisen, sofern dies der sachlichen Forderung oder schnelleren Erledigung der Verfahren dienlich ist. <sup>2</sup>Die Landesregierungen können diese Ermächtigung auf die Landesjustizverwaltungen übertragen.
: <sup>1)</sup> Beachte hierzu Übergangsvorschrift in § 31 EGZPO (Nr. 1a).
= § 32c Ausschließlicher Gerichtsstand bei Musterfeststellungsverfahren. =
Für Klagen in Musterfeststellungsverfahren nach Buch 6 ist das Gericht des allgemeinen Gerichtsstands des Beklagten ausschließlich zuständig, sofern sich dieser im Inland befindet.
'''(Quellinfo = Buch "ZPO" S. 28 ff.)'''
= § 33 Besonderer Gerichtsstand der Widerklage. =
(1) Bei dem Gericht der Klage kann eine Widerklage erhoben werden, wenn der Gegenanspruch mit dem in der Klage geltend gemachten Anspruch oder mit den gegen ihn vorgebrachten Verteidigungsmitteln in Zusammenhang steht. (2) Dies gilt nicht, wenn für eine Klage wegen des Gegenanspruchs die Vereinbarung der Zuständigkeit des Gerichts nach § 40 Abs. 2 unzulässig ist. '''(Quellinfo = Buch "ZPO" S. 28 ff.)'''
= § 34 Besonderer Gerichtsstand des Hauptprozesses. =
Für Klagen der Prozessbevollmächtigten, der Beistände, der Zustellungsbevollmächtigten und der Gerichtsvollzieher wegen Gebühren und Auslagen ist das Gericht des Hauptrozesses zuständig. '''(Quellinfo = Buch "ZPO" S. 28 ff.)'''
= § 35 Wahl unter mehreren Gerichtsständen. =
Unter mehreren zuständigen Gerichten hat der Kläger die Wahl. '''(Quellinfo = Buch "ZPO" S. 28 ff.)'''
= § 35a (aufgehoben) =
= § 36 Gerichtliche Bestimmung der Zuständigkeit.=
(1) Das zuständige Gericht wird durch das im Rechtszug zunächst höhere Gericht bestimmt:1. wenn das an sich zuständige Gericht in einem Einzelnen Fall an der Ausübung des Richteramtes rechtlich oder tatsächlich verhindert ist; 2. wenn es mit Rücksicht auf die Grenzen verschiedener Gerichtsbezirke ungewiss ist, welches Gericht für den Rechtsstreit zuständig sei; 3. wenn mehrere Personen, die bei verschiedenen Gerichten ihren allgemeinen Gerichtsstand haben als Streitgenossen im allgemeinen Gerichtstand verklagt werden sollen und für den Rechtsstreit ein gemeinschaftlicher besonderer Gerichtstand nicht begründet ist; 4. wenn die Klage in den dinglichen Gerichtsstand erhoben werden soll und die Sache in den Bezirken verschiedener Gerichte belegen ist; 5. wenn in einem Rechtsstreit verschiedene Gerichte sich rechtskräftig für zuständig erklärt haben; 6. wenn verschiedene Gerichte, von denen eines für den Rechtsstreit zuständig ist, sich rechtskräftig für unzuständig erklärt haben,
(2) Ist das zunächst höhere gemeinschaftliche Gericht der Bundesgerichtshof, so wird das zuständige Gericht durch das Oberlandesgericht bestimmt, zu dessen Bezirk das zuerst mit der Sache befasste Gericht gehört. '''(Quellinfo = Buch "ZPO" S. 28 ff.)'''
= § 37 Verfahren bei gerichtlicher Bestimmung. =
(1) Die Entscheidung über das Gesuch um Bestimmung des zuständigen Gerichts ergeht durch Beschluss. (2) Der Beschluss, der das zuständige Gericht bestimmt, ist nicht anfechtbar.
'''(Quellinfo = Buch "ZPO" S. 29 ff.)'''
:::'''Titel 3. Vereinbarung über die Zuständigkeit des Gerichts'''
= § 38 Zugelassene Gerichtsstandsvereinbarung =
(1) Ein an sich unzuständiges Gericht des ersten Rechtszuges wird durch ausdrückliche oder stillschweigende Vereinbarung der Parteien zuständig, wenn die Vertragsparteien Kaufleute, juristische Personen des öffentlichen Rechts oder öffentlich-rechtliche Sondervermögen sind. (2)<sup>1)</sup> <sup>1</sup> Die Zuständigkeit eines Gerichts des ersten Rechtszuges kann ferner vereinbart werden, wenn mindestens eine der Vertragsparteien keinen allgemeinen Gerichtsstand in Inland hat. <sup>2</sup> Die Vereinbarung muss schriftlich abschlossen oder, falls sie mündlich getroffen wird, schriftlich bestätigt werden.<sup>3</sup>Hat eine der Parteien einen inländischen allgemeinen Gerichtsstand, so kann für das Inland nur ein Gericht gewählt werden, bei dem diese Partei ihren allgemeinen Gerichtstand hat oder ein besonderer Gerichtstand begründet ist.(3) Im Übrigen ist eine Gerichtsstandsvereinbarung nur zulässig, wenn sie ausdrücklich und schriftlich 1. nach dem Entstehen der Streitigkeit oder 2. für den Fall geschlossen wird, das die im Klageweg in Anspruch zu nehmende Partei nach Vertragsschluss ihren Wohnsitz oder gewöhnlichen Aufenthaltsort aus dem Geltungsbereich dieses Gesetztes verlegt oder ihr Wohnsitz oder gewöhnlicher Aufenthalt im Zeitpunkt der Klageerhebung nicht bekannt ist. '''(Quellinfo = Buch "ZPO" S. 29 ff.)'''
= § 39 Zuständigkeit infolge rügeloser Verhandlung. =
<sup>1</sup>Die Zuständigkeit eines Gericht des ersten Rechtszuges wird ferner dadurch begründet, dass der Beklagte, ohne die Unzuständigkeit geltend zu machen, zur Hauptsache mündlich verhandelt. <sup>2</sup>Dies gilt nicht, wenn die Belehrung nach § 504 unterblieben ist. '''(Quellinfo = Buch "ZPO" S. 29 ff.)'''
= § 40 Unwirksame und unzulässige Gerichtsstandsvereinbarung. =
(1) Die Vereinbarung hat keine rechtliche Wirkung, wenn sie nicht auf ein bestimmtes Rechtsverhältnis und die aus ihm entspringenden Rechtsstreitigkeiten sich bezieht. (2) Eine Vereinbarung is unzulässig, wenn 1. der Rechtsstreit nichtvermögensrechtliche Ansprüche betrifft, die den Amtsgerichten ohne Rücksicht auf den Wert des Streitgegenstandes zugewiesen sind, oder 2. für de Klage ein ausschließlicher Gerichtsstand begründet ist. <sup>2</sup> In diesen Fällen wird die Zuständigkeit eines Gerichts auch nicht durch rügeloses Verhandeln zur Hauptsache begründet. '''(Quellinfo = Buch "ZPO" S. 29 ff.)'''
:::'''Titel 4. Ausschließung und Ablehnung der Gerichtspersonen'''
= § 41 Ausschluss von der Ausübung des Richteramtes. =
Ein Richter ist von der Ausübung des Richteramtes kraft Gesetzes ausgeschlossen; 1. in Sachen, in denen er selbst Partei ist oder bei denen er zu einer Partei in dem Verhältnis eines Mitberechtigten, Mitverpflichteten oder Regresspflichtigen steht;2. in Sachen eines Ehegatten, auch wenn die Ehe nicht mehr besteht; 2a. in Sachen seines Lebenspartners, auch wenn die Lebenspartnerschaft nicht mehr besteht. 3. in Sachen einer Person, mit der er in gerader Linie verwandt oder verschwägert, in der Seitenlinie bis zum dritten Grad verwandt oder bis zum zweiten Grad verschwägert ist oder war; 4. in Sachen, in denen er als Prozessbevollmächtigter oder Beistand einer Partei bestellt oder als gesetzlicher Vertreter einer Partei aufzutreten berechtigt ist oder gewesen ist; 5. in Sachen, in denen er als Zeuge oder Sachverständiger vernommen ist; 6. in Sachen, in denen er in einem früheren Rechtszug oder im schiedsrichterlichen Verfahren bei dem Erlass der angefochtenen Entscheidung mitgewirkt hat, sofern er sich nicht um die Tätigkeit eines beauftragten oder ersuchten Richters handelt; 7. in Sachen wegen überlanger Gerichtsverfahren, wenn er in dem beanstandeten Verfahren in einem Rechtszug mitgewirkt hat, auf dessen Dauer der Entschädigungsanspruch gestützt wird; 8. in Sachen, in denen er an einem Meditationsverfahren oder einem anderen Verfahren der außergerichtlichen Konlikbeilegung mitgewirkt hat.
= § 42 Ablehnung eines Richters. =
(1) Ein Richter kann sowohl in den Fällen, in denen er von der Ausübung des Richteramts kraft Gesetzes ausgeschlossen ist, als auch wegen Besorgnis der Befangenheit abgelehnt werden. (2) Wegen Besorgnis der Befangenheit findet die Ablehnung statt, wenn ein Grund vorliegt, der geeignet ist, Misstrauen gegen die Un parteilichkeit eines Richters zu rechtfertigen. (3) Das Ablehnungsrecht steht in jedem Fall beiden Parteien zu. '''(Quellinfo = Buch "ZPO" S. 29 ff.)'''
= § 43 Verlust des Ablehnungsrechts. =
Eine Partei kann einen Richter wegen Besorgnis der Befangenheit nicht mehr ablehnen, wenn sie sich bei ihm, ohne den ihr bekannten Ablehnungsgrund geltend zu machen, in eine Verhandlung eingelassen oder Anträge gestellt hat. '''(Quellinfo = Buch "ZPO" S. 31 ff.)'''
= § 44 Ablehnungsgesuch. =
(1) Das Ablehnungsgesuch ist bei dem Gericht, dem der Richter angehört, anzubringen; es kann vor der Geschäftsstelle zu Protokoll erklärt werden. (2)<sup>1</sup>Der Ablehnungsgrund ist glaubhaft zu machen, zur Versicherung an Eides statt darf die Partei nicht zugelassen werden. <sup>2</sup>Zur Glaubhaftmachung kann auf das Zeugnis des abgelehnten Richters Bezug genommen werden. (3) Der abgelehnte Richter hat sich über den Ablehnungsgrund dienstlich zu äußern. (4)<sup>1</sup>Wird ein Richter, bei dem die Partei sich in eine Verhandlung eingelassen oder Anträge gestellt hat, wegen Besorgnis der Befangenheit abgelehnt, so ist glaubhaft zu machen, dass der Ablehnungsgrund erst später entstanden oder der Partei bekannt geworden sei.<sup>2</sup>Das Ablehnungsgesuch ist unverzüglich anzubringen. '''(Quellinfo = Buch "ZPO" S. 31 ff.)'''
= § 45 Entscheidung über das Ablehnungsgesuch. =
(1)Über das Ablehnungsgesuch entscheidet das Gericht, dem der Abgelehnte angehört, ohne dessen Mitwirkung. (2)<sup>1</sup>Wird ein Richter beim Amtsgericht abgelehnt, so entscheidet ein anderer Richter des Amtsgerichts über das Gesuch.<sup>2</sup>Einer Entscheidung bedarf es nicht, wenn der abgelehnte Richter das Ablehnungsgesuch für begründet hält. (3)Wird das zur Entscheidung berufene Gericht durch Ausscheiden des abgelehnten Mitglieds beschlussunfähig, so entscheidet das im Rechtszug zunächst höhere Gericht. '''(Quellinfo = Buch "ZPO" S. 31 ff.)'''
= § 46 Entscheidung und Rechtsmittel. =
(1)Die Entscheidung über das Ablehnungsgesuch ergeht durch Beschluss. (2)Gegen den Beschluss, durch den das Gesuch für begründet erklärt wird findet kein Rechtsmittel, gegen den Beschluss, durch den das Gesuch für unbegründet erklärt wird, findet sofortige Beschwerde statt. '''(Quellinfo = Buch "ZPO" S. 31 ff.)'''
= § 47 Unaufschiebbare Amtshandlungen. =
(1) Ein abgelehnter Richter hat vor Erledigung des Ablehnungsgesuchs nur solche Handlungen vorzunehmen, die keinen Aufschub gestatten. (2)<sup>1</sup>Wird ein Richter während der Verhandlung abgelehnt und würde die Entscheidung über die Ablehnung eine Vertagung der Verhandlung erfordern, so kann der Termin unter Mitwirkung des abgelehnten Richters fortgesetzt werden.<sup>2</sup>Wird die Ablehnung für begründet erklärt, so ist der nach Anbringung des Ablehnungsgesuchs liegende Teil der Verhandlung zu wiederholen. '''(Quellinfo = Buch "ZPO" S. 31 ff.)'''
= § 48 Selbstablehnung: Ablehnung von Amts wegen. =
Das für die Erledigung eines Ablehnungsgesuchs zuständige Gericht hat auch dann zu entscheiden, wenn ein solches Gesuch nicht angebracht ist, ein Richter aber von einem Verhältnis Anzeige macht, das eine Ablehnung rechtfertigen könnte, oder wenn aus anderer Veranlassung Zweifel darüber entstehen, ob ein Richter kraft Gesetzes ausgeschlossen sei. '''(Quellinfo = Buch "ZPO" S. 31 ff.)'''
= § 49 Urkundsbeamte. =
Die Vorschriften dieses Titels sind auf den Urkundsbeamten der Geschäftsstelle entsprechend anzuwenden; die Entscheidung ergeht durch das Gericht, bei dem er angestellt ist.
:::::::'''Abschnitt 2 Parteien'''
::::'''Titel 1. Parteifähigkeit: Prozessfähigkeit'''
= § 50 Parteifähigkeit. =
(1) Parteifähig ist, wer rechtsfähig ist. (2) Ein Verein, der nicht rechtsfähig ist, kann klagen und verklagt werden; in dem Rechtsstreit hat der Verein die Stellung eines rechtsfähigen Vereins.
= § 51 Prozessfähigkeit; gesetzliche Vertretung; Prozessführung. =
(1) Die Fähigkeit einer Partei, vor Gericht zu stehen, die Vertretung nicht prozessfähiger Parteien durch andere Personen (gesetzliche Vertreter) und die Notwendigkeit einer besonderen Ermächtigung zur Prozessführung bestimmt sich nach den Vorschriften des bürgerlichen Rechts, soweit nicht die nachfolgenden Paragraphen abweichende Vorschriften enthalten. (2) Das Verschulden eines gesetzlichen Vertreters steht dem Verschulden der Partei gleich. (3) Hat eine nicht prozessfähige Partei, die eine volljährige natürliche Person ist, wirksam eine andere natürliche Person schriftlich mit ihrer gerichtlichen Vertretung bevollmächtigt, so steht diese Person einem gesetzlichen Vertreter gleich, wenn die Bevollmächtigung geeignet ist, gemäß '''''[''bis 31.12.2022:'''§ 1896 Abs. 2 Satz 2 des Bürgerlichen Gesetzbuchs'']''''' [ab 1.1.2023:''' ''§ 1814 Absatz 3 Satz 2 Nummer 1 des Bürgerlichen Gesetzbuchs''']''''' die Erforderlichkeit einer Betreuung entfallen zu lassen.
= § 52 Umfang der Prozessfähigkeit. =
(1)<sup>1</sup> Eine Person ist insoweit prozessfähig, als sie sich durch Verträge verpflichten kann
= § 53 Prozessfähigkeit bei Betreuung oder Pflegschaft. =
''[§ 53 bis 31.12.2022:]''
Wird in einem Rechtsstreit eine prozessfähige Person durch einen Betreuer oder Pfleger vertreten, so steht sie für den Rechtsstreit einer nicht prozessfähigen Person gleich.
= § 53 Prozessfähigkeit bei rechtlicher Betreuung. =
''[§ 53 ab 1.1.2023:]''
(2) Bei Personen, für die ein Betreuer bestellt ist, richtet sich die Prozessfähigkeit nach den allgemeinen Vorschriften.(2)<sup>1</sup>Wird ein Betreuer in einem Rechtsstreit durch einen Betreuer vertreten, kann der Betreuer in jeder Lage des Verfahrens gegenüber dem Prozessgericht schriftlich oder zu Protokoll der Geschäftsstelle erklären, dass der Rechtsstreit fortan ausschließlich durch ihn geführt wird (Ausschließlichkeitserklärung).<sup>2</sup>Mit Eingang der Ausschließlichkeitserklärung steht der Betreute für den weiteren Rechtsstreit einer nicht prozessfähigen Person gleich.<sup>3</sup>Der Betreuer kann die Ausschließlichkeitserklärung jederzeit mit Wirkung für die Zukunft zurücknehmen.
= § 53a =
(aufgehoben)
= § 54 Besondere Ermächtigung zu Prozesshandlungen. =
Einzelne Prozesshandlungen, zu denen nach den Vorschriften des bürgerlichen Rechts eine besondere Ermächtigung erforderlich ist, sind ohne sie gültig, wenn die Ermächtigung zur Prozessführung im Allgemeinen erteilt oder die Prozessführung auch ohne eine solche Ermächtigung im Allgemeinen statthaft ist. '''(Quellinfo = Buch "ZPO" S. 32 ff.)'''
= § 55 Prozessfähigkeit von Ausländern. =
Ein Ausländer, dem nach dem Recht seines Landes die Prozessfähigkeit mangelt, gilt als prozessfähig, wenn ihm nach dem Recht des Prozessgerichts die Prozessfähigkeit zusteht. '''(Quellinfo = Buch "ZPO" S. 33 ff.)'''
= § 56 Prüfung von Amts wegen. =
(1) Das Gericht hat den Mangel der Parteifähigkeit, der Prozessfähigkeit, der Legitimation eines gesetzlchen Vetreters und der erforderlichen Ermächtigung zur Prozessführung von Amts wegen zu berücksichtigen. '''(Quellinfo = Buch "ZPO" S. 33 ff.)'''
= § 57 Prozesspfleger. =
(1) Soll eine nicht prozessfähige Partei verklagt werden, die ohne gesetzlichen Vertreter ist, so hat ihr der Vorsitzende des Prozess-Eintritt des gesetzten Vertreters einen besonderen Vertreter zu bestellen.
'''(Quellinfo = Buch "ZPO" S. 33 ff.)'''
= § 58 Prozesspfleger bei herrenlosem Grundstück oder Schiff. =
(1) Soll ein Recht an einem Grundstück, das von dem bisherigen Eigentümer nach § 928 des Bürgerlichen Gesetzbuchs aufgegeben und von dem Aneignungsberechtigten noch nicht erworben worden ist,im Wege der Klage geltend gemacht werden, so hat der Vorsitzende des Prozessgerichts auf Antrag einen Vertreter zu bestellen, dem bis zur Eintragung eines neuen Eigentümers die Wahrnehmung, der sich aus dem Eigentum ergebenden Rechte und Verpflichtungen im Rechtsstreit obliegt. (2) Absatz 1 gilt entsprechend, wenn im Wege der Klage ein Recht an einem eingetragenen Schiff oder Schiffsbauwerk geltend gemacht werden soll, da von dem bisherigen Eigentümer nach § 7 des Gesetztes über Rechte an eingetragenen Schiffen und Schiffsbauwwerken vom 15. November 1940 (RGB1. IS. 1499) aufgegeben und von Aneignungsberechtigten noch nicht erworben worden ist. '''(Quellinfo = Buch "ZPO" S. 33 ff.)'''
:::'''Titel 2. Streitgenossenschaft'''
= § 59 Streitgenossenschaft bei Rechtsgemeinschaft oder Identität des Grundes. =
Mehrere Personen können als Streitgenossen gemeinschaftlich klagen oder verklagt werden, wenn Sie hinsichtlich des Streitgegenstandes in Rechtsgemeinschaft stehen oder wenn sie aus demselben tatsächlichen und rechtlichen Grund berechtigt oder verpflichtet sind.
= § 60 Streitgenossenschaft bei Gleichartigkeit der Ansprüche. =
Mehrere Personen können auch dann als Streitgenossen gemeinschaftlich klagen oder verklagt werden, wenn gleichartige und auf einem im Wesentlichen gleichartigen tatsächlichen und rechtlichen Grund beruhende Ansprüche oder Verpflichtungen. den Gegenstand des Rechtsstreits bilden. '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
= § 61 Wirkung der Streitgenossenschaft. =
Streitgenossen stehen, soweit nicht aus den Vorschriften des bürgerlichen Rechts oder dieses Gesetzes sich ein anderes egibt, dem Gegner dergestallt als Einzelne <sup>1)</sup> gegenüber, dass die Handlungen des einen Streitgenossen dem anderen weder zum Vorteil noch zum Nachteil gereichen. '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
= § 62 Notwendige Streitgenossenschaft. =
(1) Kann das streitige Rechtsverhäntlnis allen Streigenossen gegenüber nur einheitlich festgestellt werden oder werden, wenn ein Termin oder eine Frist nur von einzelnen Streitgenosen versäumt wird, die säumigen Steitgenossen als durch die nicht säumigen vertreten angesehen. (2) Die säumigen Streitgenossen ind auch in dem späteren Verfahren zuzuziehen. '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
= § 63 Prozessbetrieb; Ladungen. =
Das Recht zur Betreibung des Prozesses steht jedem Streitgenossen zu; zu allen Terminen sind sämtliche Streitgenossen zu laden: '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
:::'''Titel 3. Beteiligung Dritter am Rechtsstreit'''
= § 64 Hauptintervention. =
Wer die Sache oder das Recht, worüber zwischen anderen Personen ein Rechtsstreit anhängig geworden ist, ganz oder teilweise für sich in Anspruch nimmt, ist bis zur rechtskräftigen Entscheidung dieses Rechtsstreits berechtigt, seinen Anspruch durch eine gegen beide Parteien gerichtete Klage bei dem Gericht geltend zu machen, vor dem der Rechtsstreit im ersten Rechtszug anhängig wurde. '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
= § 65 Aussetzung des Hauptprozesses. =
Der Hauptprozess kann auf Antrag einer Partei bis zur rechtskräfigten Entscheidung über die Hauptintervention ausgesetzt werden. '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
= § 66 Nebenintervention. =
(1) Wer ein rechtliches Interesse daran hat, dass in einem zwischen anderen Personen anhängigen Rechtsstreit die eine Partei obsiege, kann dieser Partei zum Zwecke ihrer Unterstützung beitreten. (2) Die Nebenintervention kann in jeder Lage des Rechtsstreits bis zur rechtskräftigen Entscheidung auch in Verbindung mit der Einlegung eines Rechtsmittels, erfolgen. '''(Quellinfo = Buch "ZPO" S. 34 ff.)'''
= § 67 Rechtsstellung des Nebenintervenienten. =
<sup>1</sup>Der Nebenintervenient muss den Rechtsstreit in der Lage annehmen, in der er sich zur Zeit seinss Beitritts befindet; er ist berechtigt, Angriffs- und Verteidigungsmittel geltend zu machen und alle Prozeesshanduungen wirksam vorzunehmen, insoweit nicht seine Erklärungen und Handlungen mit Erklärungen und Handlungen der Hauptpartei in Widerspruch stehen. <sup>2</sup>Für ihn gelten die §§ 141 und 278 Absatz 3 entsprechend.
= § 68 Wirkung der Nebenintervention. =
Der Nebenintervenient wird im Verhältnis zu der Hauptpartpartei mit der Behauptung nicht gehört, dass der Rechtsstreit, wie er dem Richter vorgelegt habe, unrichtig entscheiden sei; er wird mit der Behauptung, das die Hauptpartei den Rechtsstreit mangelhaft geführt habe, nur insoweit gehört, als er durchh die Lage des Rechtsstreits zur Zeit seines Beitritts oder durch Erklärungen und Handlungen der Hauptpartei verhindert worden ist, Angriffs- oder Verteidigungsmittel geltend zu machen, oder als Angriffs- oder Verteidigungsmittel, die ihm unbekannt waren, von der Hauptpartei absichtlich oder durch grobes Verschulden nicht geltend gemacht sind.
= § 69 Streitgenössische Nebenintervention. =
Insofern nach den Vorschriften des bürgerliches Rechts die Rechtskraft der in dem Hauptprozess erlassenen Entscheidung auf das Rechtsverhältnis des Nebenintervenienten zu dem Gegner von Wirksamkeit ist, gilt der Nebenintervenient im Sinne des § 61 als Streitgenosse de Hauptpartei.
= § 70 Beitritt des Nebenintervenienten. =
(1) <sup>1</sup> Der Beitritt des Nebenintervenienten erfolgt durch Einreichung eines Schriftsatzes bei dem Prozessgericht und, wenn er mit der Einlegung eines Rechtsmitels verbunden wird, durch Einreichung eines Schriftsatzes bei dem Rechtsmittelgericht. <sup>2</sup> Der Schriftsatz ist beiden Parteien zuzustellen und muss enthalten:<br> 1. die Bezeichnung der Parteien und des Rechtssteireits; <br> 2. die bestimmte Angabe des Interesses, das der Nebenintervenient hat; <br>3. die Erklärung des Beitritts.
:(2) Außerdem gelten die allgemeinen Vorschriften über die vorbereitenden Schriftsätze. ''(Quellinfo = Buch "ZPO" S. 35 ff.)'''
= § 71 Zwischenstreit über Nebenintervention. =
(1)<sup>1</sup> Über den Antrag auf Zurückweisung einer Nebenintervention wird nach mündlicher Verhandlung unter den Parteien und dem Nebenintervenienten entschieden.<sup>2</sup> Der Nebenintervenient ist zuzulassen, wenn er sei Interesse glaubhaft macht.<br> (2) Gegen das Zwischenurteil findet sofortige Beschwerde statt.<br> (3) Solange nicht die Unzulässigkeit der Intervention rechtskräftig ausgesprochen ist, wird der Intervenient im Hauptverfahren zugezogen. ''(Quellinfo = Buch "ZPO" S. 35 ff.)'''
= § 72 Zulässigkeit der Streitverkündigung. =
(1) Eine Partei, die für den Fall des ihr ungünstigen Ausganges des Rechtsstreits einen Anspruch auf Gewährleistung oder Schadloshaltung gegen einen Dritten erheben zu können glaubt oder den Anspruch eines Dritten besorgt, kann bis zur rechtskräftigen Entscheidung des Rechtsstreits dem Dritten gerichtlich den Streit verkünden.<br> (2)<sup>1</sup> Das Gericht und ein vom Gericht ernannter Sachverständiger sind nicht Dritter im Sinne dieser Vorschrift. <sup>2</sup>§73 Satz 2 ist nicht anzuwenden.<br> (3) Der Dritte ist zu einer weiteren Streitverkündung berechtigt. '''(Quellinfo = Buch "ZPO" S. 35 ff.)'''
= § 73 Form der Streitverkündigung. =
<sup>1</sup>Zum Zwecke der Streitverkündung hat die Partei einen Schriftsatz einzureichen, in dem der Grund der Streitverkündung und die Lage des Rechtsstreits anzugeben ist. <sup>2</sup>Der Schriftsatz ist dem Dritten zuzustellen und dem Gegner des Streitverkünders in Abschrift mitzuteilen. <sup>3</sup>Die Streitverkündung wird erst mit der Zustellung an den Dritten wirksam.'''(Quellinfo = Buch "ZPO" S. 35 ff.)'''
= § 74 Wirkung der Streitverkündigung. =
(1) Wenn der Dritte dem Streitverkünder beitritt, so bestimmt sich sein Verhältnis zu den Parteien nach den Grundsätzen über die Nebenintervention. <br> (2) Lehnt der Dritte den Beitritt ab oder erklärt er sich nicht, so wird der Rechtsstreit ohne Rücksicht auf ihn fortgesetzt. <br> (3) In allen Fällen dieses Paragraphen sind gegen den Dritten die Vorschriften des § 68 mit der Abweichung anzuwenden, dass statt der Zeit des Beitritts die Zeit entscheidet, zu welcher der Beitritt infolge der Streitverkündung möglich war. '''(Quellinfo = Buch "ZPO" S. 36 ff.)'''
= § 75 Gläubigerstreit. =
<sup>1</sup>Wird von dem verklagten Schuldner einem Dritten, der die geltend gemachte Forderung für sich in Anspruch nimmt, der Streit verkündet und tritt der Dritte in den Streit ein, so ist der Beklagte, wenn er den Betrag der Forderung zugunsten der streitenden Gläubiger unter Verzicht auf das Recht zur Rücknahme hinterlegt, auf seinen Antrag aus dem Rechtsstreit unter Verurteilung in die durch seinen unbegründeten Widerspruch veranlassten Kosten zu entlassen und der Rechtsstreit über die Berechtigung an der Forderung zwischen den streitenden Gläubigern allein fortzusetzen.<sup>2</sup>Dem Obsiegenden ist der hinterlegte Betrag zuzusprechen und der Unterliegende auch zur Erstattung der dem Beklagten entstandenen, nicht durch dessen unbegründeten Widerspruch veranlassten Kosten, einschließlich der Kosten der Hinterlegung zu verurteilen.
= § 76 Urheberbenennung bei Besitz. =
(1)<sup>1</sup>Wer als Besitzer einer Sache verklagt ist, die er auf Grund eines Rechtsverhältnisse der im § 868 des Bürgerlichen Gesetzbuchs bezeichneten Art zu besitzen behauptet, kann vor der Verhandlung zur Hauptsache unter Einreichung eines Schriftsatzes, in dem er den mittelbaren Besitzer benennt, und einer Streiverkündigungsschrift die Ladung des mittelbaren Besitzers zur Erklärung beantragen.<sup>2</sup> Bis zu dieser Erklärung oder bis zum Schluss des Termins, in dem sich der Benannte zu erklären hat, kann der Beklagte die Verhandlung zur Hauptsache verweigern. <br> (2) Bestreitet der Benannte die Behauptung des Beklagten oder erklärt er sich nicht, so ist der Beklagte berechtigt, dem Klageantrage zu genügen. <br> (3)<sup>1</sup>Wird die Behauptung des Beklagten von dem Benannten als richtig anerkannt, so ist dieser berechtigt, mit Zustimmung des Beklagten an dessen Stelle zu übernehmen.<sup>2</sup>Die Zustimmung des Klägers ist nur insoweit erforderlich, als er Ansprüche geltend macht, die unabhängig davon sind, dass der Beklagte auf Grund eines Rechtsverhältnisses der im Absatz 1 bezeichneten Art besitzt.<br>(4)<sup>1</sup>Hat der Benannte den Prozess übernommen, so ist der Beklagte auf seinen Antrag von der Klage zu entbinden.<sup>2</sup>Die Entscheidung ist in Ansehung der Sache selbst auch gegen den Beklagten wirksam und vollstreckbar.
= § 77 Urheberbenennung bei Eingentumsbeeinträchtigung. =
Ist von dem Eigentümer einer Sache oder von demjenigen, dem ein Recht an einer Sache zusteht, wegen einer Beeinträchtigung des Eigentums oder seines Rechts Klage auf Beseitigung der Beeinträchtigung oder auf Unterlassung weiter Beeinträchtigungen erhoben, so sind die Vorschriften des § 76 entsprechend an eines Dritten vorgenommen zu haben behauptet.
= § 78 Anwaltsprozess. =
= § 78a =
(weggefallen)
= § 78b Notanwalt. =
(1) Insoweit eine Vertretung durch Anwälte geboten ist, hat das Prozessgericht einer Partei auf ihren Antrag durch Beschluss für den Rechtszug einen Rechtsanwalt zur Wahrnehmung ihrer Rechte beizuordnen, wenn sie einen zu ihrer Vertretung bereiten Rechtsanwalt nicht findet und die Rechtsverfolgung oder Rechtsverteidigung nicht mutwillig oder aussichtslos erscheint. (2) Gegen den Beschluss, durch den die Beiordnung eines Rechtsanwalts abgelehnt wird, findet die sofortige Beschwerde statt.
= § 78c Auswahl des Rechtsanwalts. =
= § 79 Parteiprozess. =
= § 80 Prozessvollmacht. =
<sup>1</sup>Die Vollmacht ist schriftlich zu den Gerichtsakten einzureichen. <sup>2</sup>Sie kann nachgereicht werden; hierfür kann das Gericht eine Frist bestimmen.
= § 81 Umfang der Prozessvollmacht. =
= § 82 Geltung für Nebenverfahren. =
Die Vollmacht für den Hauptprozess umfasst die Vollmacht für das eine Hautintervention, einen Arrest oder eine einstweilige Verfügung betreffende Verfahren. '''(Quellinfo = Buch "ZPO" S. 39 ff.)'''
= § 83 Beschränkung der Prozessvollmacht. =
= § 84 Mehrere Prozessbevollmächtigte. =
<sup>1</sup>Mehrere Bevollmächtigte sind berechtigt, sowohl gemeinschaftlich als einzeln die Partei zu vertreten. <sup>2</sup>Eine abweichende Bestimmung der Vollmacht hat dem Gegner gegenüber keine rechtliche Wirkung
= § 85 Wirkung der Prozessvollmacht. =
= § 86 Fortbestand der Prozessvollmacht. =
= § 87 Erlöschen der Vollmacht. =
= § 88 Mangel der Vollmacht. =
= § 89 Vollmachtloser Vertreter. =
= § 90 Beistand. =
::::::::::::: '''Titel 5 Prozesskosten'''
= § 91 Grundsatz und Umfang der Kostenpflicht. =
= § 91a Kosten bei Erledigung der Hauptsache. =
= § 92 Kosten bei teilweisem Obsiegen. =
= § 93 Kosten bei sofortigem Anerkenntnis. =
= § 93a =
(aufgehoben)
= § 93b Kosten bei Räumungsklagen. =
= § 93c, 93d =
= § 94 Kosten bei übergegangenem Anspruch. =
= § 95 Kosten bei Säumnis oder Verschulden. =
= § 96 Kosten erfolgloser Angriff- oder Verteidigungsmittel. =
= § 97 Rechtsmittelkosten. =
= § 98 Vergleichtskosten. =
= § 99 Anfechtung von Kostenentscheidungen. =
= § 100 Kosten bei Streitgenossen. =
= § 101 Kosten einer Nebenintervention. =
= § 102 =
(weggefallen)
= § 103 Kostenfestsetzungsgrundlage: Kostenfestsetzungsantrag. =
= § 104 Kostenfestsetzungsverfahren =
= § 105 Vereinfachter Kostenfestsetzungsbeschluss. =
= § 106 Verteilung nach Quoten. =
= § 107 Änderung nach Streitwertfestsetzung. =
(1)<sup>1</sup> Ergeht nach der Kostenfestsezung eine Entscheidung, durch die der Wert des Streitgegenstandes festgesetzt wird, so ist, falls diese Entscheidung von der Wertberechnung abweicht, die der Kostenfestsetzung zugrunde liegt, auf Antrag die Kostengestsetzung entsprechend abzuändern.<sup>2</sup>Über den Antrag entscheidet das Gericht des ersten Rechtszuges. (2) <sup>1</sup> Der Antrag ist binnen der Frist von einem Monat bei der Geschäftsstelle anzubringen. <sup>2</sup>Die Frist beginnt mit der Zustellung und wenn es einer solchen nicht bedarf, mit der Verkündung des den Wert des Streitgegenstandes festsetzenden Beschlusses. (3) Die Vorschriften des § 104 Abs. 3 sind anzuwenden.'''(Quellinfo = Buch "ZPO" S. 45 ff.)'''
= § 108 Art und Höhe der Sicherheit. =
= § 109 Rückgabe der Sicherheit. =
= § 110<sup>1)</sup> Prozesskostensiocherheit. =
= § 111 Nachträgliche Prozesskostensicherheit. =
= § 112 Höhe der Prozesskostensicherheit. =
= § 113 Fristbestimmung für Prouesskostensicherheit. =
(1) <sup>1</sup>Das Gericht hat dem Kläger bei Anordnung der Sicherheitsleistung eine Frist zu bestimmen, binnen der die Sicherheit zu leisten ist. <sup>2</sup>Nach Ablauf der Frist ist auf Antrag des Beklagten, wenn die Sicherheit bis zur Entscheidung nicht geleistet ist. die Klage für zurückgenommen zu erklären oder, wenn über ein Rechtsmittel des Klägers zu verhandeln ist, dieses zu verwerfen.
::::::::::::: '''Titel 7 Prozesskostenhilfe<sup>1</sup> und Prozesskostenvorschuss'''
= § 115 Einsatz von Einkommen und Vermögen. =
(1) <sup>1</sup>Die Partei hat ihr Einkommen einzusetzen. <sup>2</sup>Zum Einkommen gehören alle Einkünfte in Geld oder Geldwert. <sup>3</sup>Von ihm sin abzusetzen: 1. a) die in §82 Abs. 2 des Zwölften Buches Sozialgesetzbuch<sup>2)</sup>bezeichneten Beträge: '''(Quellinfo = Buch "ZPO" S. 46 ff.)'''
=____________________________________________________________________=
<sup>1</sup>Vgl. Art. 220 bis 24 Haager Übereinkommen über den Zivilprozess v. 1.3.1954 (BGB1. 1958 II S 576, 577). Siehe ferner § 11 G über die Rechtsstellung heimatloser Ausländer im Bundesgebiet v. 25.4.1951 (BGB1 I.S. 269), zuletzt geänd. durch G v. 30.7.2004 (BGB1. I S. 1950) und für Mitglieder der in der Bundesrepublik stationierten ausländischen Truppen. vgl. Art. 31 Zusatzabkommen zum NATO-Truppenstatut v. 3.8.1959 (BGB1. 1961 II S. 1218), zuletzt geändert. durch Abk. v. 28.9.1994 (BGB1. II S. 2598).
<sup>2</sup>§ 82 Abs. 2 und 3 des Zwölften Buches Sozialgesetzbuch v. 27.12.2003 (BGB1, I S. 3022, 3023),"(2)<sup>1</sup>Von dem Einkommen sind abzusetzen <br> 1. auf die Einkommen entrichtete Steuern. <br> 2. Pflichtbeiträge zur Sozialversicherung einschließlich der Beiträge zur Arbeitsförderung. →</br>
(Fortsetzung der Anm. von voriger Seite)<br>
3. Beiträge zu öffentlichen oder privaten Versicherungen oder ähnlichen Einrichtungen, soweit diese Beiträge gesetzlich vorgeschrieben oder nach #grund und Höhe angemessen sind, sowie geförderte Altersvorsorgeverträge nach § 82 des Einkommensteuergesetzes, soweit sie den Mindeststeigenbetrag nach § 86 des Einkommensteuergesetzes nicht überschreiten, und <br>4. die mit der Erzielen des Einkommens verbundenen notwendigen Ausgaben.<br><sup>2</sup>Erhält eine leistungsberechtigte Person aus einer Tätigkeit Bezüge oder Einnahmen, die nach § 3 Nummer 12,26, 26a oder 26b des Einkommensteuergesetzes steuerfrei sind oder die als Taschengeld Jugendfreiwilligendienstegesetzes gezahlt werden, ist abweichend von Satz 1 Nummer 2 bis 4 und den Absätzen 3 und 6 ein Betrag von bis zu 250 Euro monatlich nicht als Einkommen zu berücksichtigen.<br><sup>3></sup>Soweit ein Betrag nach Satz 2 in Anspruch genommen wird, gelten die Beträge nach Absatz 3 Satz 1 zweiter Halbsatz und nach Absatz 6 Satz 1 zweiter Halbsatz insoweit als ausgeschöpft. <br>(3)<sup>1</sup>Bei der Hilfe zum Lebensunterhalt und Grundsicherung im Alter und bei Erwerbsminderung ist ferner ein Betrag in Höhe von 30 vom Hundert des Einkommens aus selbständiger und nichtselbständiger Tätigkeit der Leistungsberechtigten abzusetzen, höchstens jedoch 50 vom Hundert der Regelbedarfsstufe 1 nach der Anlage zu § 28. <sup>2</sup>Abweichend von Satz 1 ist bei einer Beschäftigung in einer Werkstatt für behinderte Menschen oder bei einem anderen Leistungsanbieter nach § 60 des Neunten Buches v. 23.12.2016 (BGB1. I S. 3234), zuletzt geändert. durch G. v 16.6.2021 (BGB1. I S. 1810) von dem Entgelt ein Achtel der Regelbedarfsstufe 1 nach der Anlage zu § 28 zuzüglich 50 vom Hundert des diesen Betrag übersteigenden Entgelts abzusetzen. <sup>3</sup>Im Übrigen kann in begründeten Fällen ein anderer als in Satz 1 festgelegter Betrag vom Einkommen abgesetzt werden."
Abschnitt 2. Parteien <br><br>
b) bei Parteien, die ein Einkommen aus Erwerbstätigkeit erzielen, ein Betrag in Höhe von 50 vom Hundert des Regelsatzes für den alleinstehenden oder alleinerziehenden Leistungsberechtigten vom Bund gemäß der Regelbedarfsstufe 1 nach der Anlage zu § 28 des Zwölften Buches Sozialgesetzbuch festgesetzt oder fortgeschrieben worden ist.<br>
2 a.) für die Partei und ihren Ehegatten oder ihren Lebenspartner jeweils ein Betrag in Höhe des um 10 vom Hundert erhöhten Regelsatzes, der für den alleinstehenden oder Alleinerziehenden Leistungsberechtigten vom Bund gemäß der Regelbedarsstufe 1 nach der Anlage zu § 28 des Zwölften Buches Sozialgesetzbuch festgesetzt oder fortgeschrieben worden ist;<br>
b) bei weiteren Unterhaltsleistungen auf Grund gesetzlicher Unterhaltspflicht für jede unterhaltsberechtigte Person jeweils ein Betrag in Höhe des um 10 vom Hundert erhöhten Regelsatzes, der für eine Person ihres Alters vom Bund gemäß den Regelbedarfsstufen 3 bis 6 nach der Anlage zu § 28 des Zwölften Buches Sozialgesetzbuch festgesetzt oder fortgeschrieben worden ist;<br>
3. die Kosten der Unterkunft und Heizung, soweit sie nicht in einem auffälligen Missverhältnis zu den Lebensverhältnissen der Partei stehen;<br>
4. Mehrbedarfe nach § 21 des Zweiten Buches Sozialgesetzbuch und nach § 30 des Zwölften Buches Sozialgesetzbuch; <br>
5. weitere Beträg, soweit dies mit Rücksicht auf besondere Belastungen angemessen ist; § 1610a dass Bürgerlichen Gesetzbuchs gilt entsprechend.<br></br>
<sup>4</sup>Maßgeblich sind die Beträge, die zum Zeitpunkt der Bewilligung der Prozesskostenhilfe gelten.<aup>5</sup>Soweit am Wohnsitz der Partei aufgrund einer Neufestsetzung oder jeder Fortschreibung nach § 20 Absatz 2 bis 4 des Zwölften Buches Sozialgesetzbuch höhere Regelsätze gelten, sind diese heranzuziehen. <sup>6</sup>Das Bundesministerium der Justiz und für Verberbraucherschutz gibt bei jeder Neufestsetzung oder jeder Fortschreibung die maßgebenden Beträge nach Satz 3 Nummer 1 Buchstabe b und Nummer 2 und nach Satz 5 im Bundesgesetzblatt bekannt. <sup>'''1)'''</sup> <sup>7</sup>Diese Beträge sind, soweit sie nicht volle Euro ergeben, bis zu 0,49 Euro abzurunden und von 0,50 Euro an aufzurunden. <sup>8</sup>Die Unterhaltsfreibeträge nach Satz 3 Nr. 2 vermindern sich um eigenes Einkommen der Unterhaltsberechtigten Person.<sup>9</sup>Wird eine Geldrente gezahlt, so ist sie anstelle des Freibetrages abzusetzen, soweit dies angemessen ist.
(2)<sup>1</sup>Von dem nach Abzügen verbleibenden Teil des monatlichen Einkommens (einzusetzendes Einkommen) sind Monatsraten in Höhe der Hälfte des einzusetzenden Einkommens festzusetzen; die Monatsraten sind auf volle Euro abzurunden. <sup>2</sup>Beträgt die Höhe einer Monatsrate weniger als 10 Euro, ist von der Festsetzung der Monatsraten abzusehen.<sup>3</sup>Bei einem einzusetzenden Einkommen von mehr als 600 Euro beträgt die Monatsrate 300 Euro zuzüglich des Teils des einzusetzenden Einkommens, der 600 Euro übersteigt.<sup>4</sup>Unabhängig von der Zahl der Rechtszüge sind höchstens 48 Monatsraten aufzubringen. (3)<sup>1</sup>Die Partei hat ihr Vermögen einzusetzen, soweit dies zumutbar ist. <sup>2</sup>§9 des Zwölften Buches Sozialgesetzbuch gilt entsprechend.(4) Prozesskostenhilfe wird nicht bewilligt, wenn die Kosten der Prozessführung der Partei vier Monatsraten und die aus dem Vermögen aufzubringenden Teilbeträge voraussichtlich nicht übersteigen.
=____________________________________________________________________=
{| class="wikitable" style="text-align: center; color: black;"
|
|Freibetrag <br> Bund <br></br>
|Freibetrag in <br>den Land-<br>kreisen Fürs-<br>tenfeldbruck<br>und<br>Starn-<br>berg</br>
|Freibetrag im <br>Landkreis<br>München<br>
|Freibetrag in <br>der Landes-<br>hauptstadt<br>München<br>
|-
|Parteien, die ein Einkommen aus Er-<br> werbtätigkeit erzielen (§ 115 Absatz 1 <br> Satz 3 Nummer 1 Buchstabe b der <br> Zivilprozessordnung)
|223 Euro
|235 Euro
|235 Euro
|234 Euro
|-
|Partei, Ehegatte oder Lebenspartner<br> (§ 115 Absatz 1 Satz 3 Nummer 2 <br> Buchstabe a der Zivilprozessverordnung) </br>
|491 Euro
|516 Euro
|517 Euro
|515 Euro
|-
|Freibetrag der unterhaltsberechtigte Er-<br> wachsene (§ 115 Absatz 1 Satz 3 Num- <br> mer 2 Buchstabe b der Zivilprozessord-<br> nungRegelbedarfsstufe 3) </br>
|393 Euro
|414 Euro
|414 Euro
|411 Euro
|-
|Freibetrag für unterhaltsberechtigte Ju- <br> endliche vom Beginn des 15. bis zur <br> Vollendung des 18. Lebensjahres (§ 115 <br> Absatz 1 Satz 3 Nummer 2 Buchstabe <br> b der Zivilprozessordnung Regelte- <br> darfstufe 4) </br>
|410 Euro
|430 Euro
|432 Euro
|429 Euro
|-
|Freibetrag für unterhaltsberechtigte <br> Kinder vom Beginn des siebten bis zur <br> Vollendung des 14. Lebensjahres (§ 115 <br> Absatz 1 Satz 3 Nummer 2 Buchstabe<br> b der Zivilprozessordnung Regel- <br> darfstufe 5) </br>
|340 Euro
|353 Euro
|359 Euro
|353 Euro
|-
|Freibetrag für unterhaltsberechtigte <br> Kinder bis zur Vollendung des sechsten <br> Lebensjahres (§ 115 Absatz 1 Satz 3<br>Nummer 2 Buchstabe b der Zivilpro- <br> zessordnung Regelbedarfsstufe 6) </br>
|311 Euro
|325 Euro
|328 Euro
|323 Euro"
|-
|}
= § 116 Partei kraft Amtes: juristische Person; parteifähige Vereinigung. =
<sup>1</sup> Prozesskostenhilfe erhalten auf Antrag 1. eine Partei kraft Amtes, wenn die Kosten aus der verwalteten Vermögensmasse nicht aufgebracht werden können und den am Gegenstand des Rechtsstreite wirtschaftlich Beteiligten nicht zuzumuten ist, die Kosten aufzubringen; 2. eine juristische Person oder parteifähige Vereinigung, die im Inland, in einem anderen Mitgliedstaat der Europäischen Union oder einem anderen Vertragsstaates des Abkommens über den Europäischen Wirtschaftsraum gegründet und dort ansässig ist, wenn die Kosten weder von ihr noch von den am Gegenstand des Rechtsstreits wirtschaftlich Beteiligten aufgebracht werden können und wenn die Unterlassung der Rechtsverfolgung oder Rechtsverteidigung allgemeinen Interessen zuwiderlaufen würde.
<sup>2</sup>§ 114 Absatz 1 Satz 1 letzter Halbsatz und Absatz 2 ist anzuwenden. <sup>3</sup> Können die Kosten nur zum Teil oder nur in Teilbeträgen aufgebracht werden, so sind die entsprechenden Beträge zu zahlen.
= § 117 Antrag. =
(1)<sup>1</sup>Der Antrag auf Bewilligung der Prozesskostenhilfe ist bei dem Prozessgericht zu stellen; er kann vor der Geschäftsstelle zu Protokoll erklärt werden. <sup>2</sup>In dem Antrag ist das Streitverhältnis unter Angabe der Beweismittel darzustellen. <sup>3</sup>Der Antrag auf Bewilligung von Prozesskostenhilfe für die Zwangsvollstreckung ist bei dem für die Zwangsvollstreckung zuständigen Gericht zu stellen.<br>(2)<sup>1</sup>Dem Antrag sind eine Erklärung der Partei über ihre persönlichen und wirtschaftlichen Verhältnisse (Familienverhältnisse, Beruf , Vermögen , Einkommen und Lasten) sowie entsprechende Belege beizufügen. <sup>2</sup>Die Erklärung und die Belege dürfen dem Gegner nur it Zustimmung der Partei zugänglich gemacht werden<sup>1)</sup>es sei denn, der Gegner hat gegen den Antragsteller nach den Vorschriften des bürgerlichen Rechts einen Anspruch auf Auskunft über Einkünfte und Vermögen des Antragstellers.<sup>3</sup>Dem Antragsteller ist vor der Übermittlung seiner Erklärung an den Gegner Gelegenheit zur Stellungnahme zu geben.<sup>4</sup>Er ist über die Übermittlung seiner Erklärung zu unterrichten.<br>(3)<sup>1</sup>Das Bundesministerium der Justiz und für Verbraucherschutz wird ermächtigt, zur Vereinfachung und Vereinheitlichung des Verfahrens durch Rechtsverordnung
<sup>2)</sup>mit Zustimmung des BundesratesFormulare für die Erklärung einzuführen.<sup>2</sup>die Formulare enthalten nach § 120a Absatz 2 Satz 4 erforderliche Belehrung.<br>(4)Soweit Formulare für die Erklärung eingeführt sind, muss sich die Partei ihrer bedienen.</br>
<sup>1)</sup>Zeichensetzung amtlich.<br>
<sup>2)</sup>Siehe die Prozesskostenhilfeformularverordnung - PKHFV v. 6.1.2014 (BGB1. I S. 34).</br>
= § 118 Bewilligungsverfahren. =
::Text folgt noch.
= § 119 Bewilligung. =
= § 120<sup>1</sup> Festsetzung von Zahlungen.=
= § 120a<sup>1</sup> Änderung der Bewilligung.=
= § 121 Beiordnung eines Rechtsanwalts.=
= § 122 Wirkung der Prozesskostenhilfe.=
= § 123 Kostenerstattung. =
Die Bewilligung der Prozesskostenhilfe hat auf die Verpflichtung, die dem Gegner entstandenen Kosten zur erstatten, keinen Einfluß.
= § 124 Aufhebung der Bewilligung.=
= § 125 Einziehung der Kosten. =
(1) Die Gerichtskosten und die Gerichtsvollzieherkosten können von dem Gegner erst eingezogen werden, wenn er rechtskräftig in die Prozesskosten verurteilt ist. (2) Die Gerichtskosten, vo deren Zahlung der Gegner einstweilen befreit ist, sind von ihm einzuziehen, soweit er rechtskräftig in die Prozesskosten verurteilt oder der Rechtsstreit ohne Urteil über die Kosten beendet ist.
= § 126 Beitreibung der Rechtsanwalskosten.=
= § 127 Entscheidungen.=
= § 140 Beanstanstandung von Prozessleitung oder Fragen. =
Wird eine auf die Sachleitung bezügliche Anordnung des Vorsitzenden oder eine von dem Vorsitzenden oder einem Gerichtsmitglied gestellte Frage von einer bei der Verhandlung beteiligten Person als unzulässig beanstandet, so entscheidet das Gericht
= § 141 Anordnung des persönlichen Erscheinens. =
(1) <sup>1</sup>Das Gericht soll das persönliche Erscheinen beider Parteien anordnen, wenn dies zur Aufklärung des Sachverhalts geboten erscheint. <sup>2</sup>Ist einer Partei wegen großer Entfernung oder aus sonstigem wichtigen Grund die persönliche Wahrnehmung des Termins nicht zuzumuten, so sieht das Gericht von der Anordnung ihres Erscheinens ab. (2)<sup>1</sup>Wird das Erscheinen angeordnet, so ist die Partei von Amts wegen zu laden. <sup>2</sup>Die Ladung ist der Partei selbst mitzuteilen, auch wenn sie einen Prozessbevollmächtigte bestellt hat; der Zustellung bedarf die Ladung nicht.(3)<sup>1</sup>Bleibt die Partei im Termin aus, so kann gegen sie Ordnungsgeld wie gegen einen im Vernehmungstermin nicht erschienen Zeugen festgesetzt werden. <sup>2</sup>Dies gilt nicht, wenn die Partei zur Verhandlung einen Vertreter entsendet, der zur Aufklärung des Tatbestandes in der Lage und zur Abgabe der gebotenen Erklärungen, insbesondere zu einem Vergleichsabschluss ermächtigt ist. <sup>3</sup>Die Partei ist auf die Folgen ihres Ausbleibens in der Ladung hinzuweisen
= § 184 Zustellungsbevollmächtigter; Zustellung durch Aufgabe zur Post. =
::Text folgt noch!
= § 185 Öffentliche Zustellung. =
Die Zustellung kann durch öffentliche Bekanntmachung (öffentliche Zustellung) erfolgen, wenn <br>1. der Aufenthaltsort einer Person unbekannt und eine Zustellung an einen Vertreter oder Zustellungsbevollmächtigten nicht möglich ist,</br> 2. bei juristischen Personen, die zur Anmeldung einer inländischen Geschäftsanschrift zum Handelsregister verpflichtet sind, eine Zustellung weder unter der eingetragenen Anschrift noch unter einer im Handelsregister eingetragenen Anschrift einer für Zustellungen empfangsberichtigten Person oder einer hohen Ermittlungen bekannten anderen inländischen Anschrift möglich ist. <br>3. eine Zustellung im Ausland nicht möglich ist oder keinen Erfolg verspricht oder </br>4. die Zustellung nicht erfolgen kann, weil der Ort der Zustellung die Wohnung einer Person ist, die nach den §§ 18 bis 20 des Gerichtsverfassungsgesetzes <sup>2)</sup> der Gerichtsbarkeit nicht unterliegt.
= § 186 Bewilligung und Ausführung der öffentlichen Zustellung. =
(1)<sup>1</sup>Über die Bewilligung der öffentlichen Zustellung entscheidet das Prozessgericht. <sup>2</sup> Die Entscheidung kann ohne mündliche Verhandlung ergehen.<br>(2)<sup>1</sup> Die öffentlichen Zustellung erfolgt durch Aushang einer Benachrichtigung an der Gerichtstafel oder durch Einstellung in ein elektronisches Informationssystem, das im Gericht öffentlich zugänglich ist <sup>2</sup> Die Benachrichtigung kann zusätzlich in einem von dem Gericht für Bekanntmachungen bestimmten elektronischen Informations- und Kommunikationssystem veröffentlicht werden. <sup>3</sup> Die Benachrichtigung muss erkennen lassen<br>1.die Person für die zugestellt wird.</br>3. das Datum, das Aktenzeichen des Schriftstücks und die Bezeichnung des Prozessgegenstandes sowie <br>4. die Stelle, wo das Schriftstück eingesehen werden kann.</br><sup>4</sup>Die Benachrichtigung muss den Hinweis enthalten, dass ein Schriftstück öffentlich zugestellt wird und Fristen in Gang gesetzt werden können, nach deren Ablauf Rechtsverluste drohen können. <sup>5</sup> Bei der Zustellung einer Ladung muss die Benachrichtigung den Hinweis enthalten, dass das Schrifstück eine Ladung zu einem Termin enthält, dessen Versäumung Rechtsnachteile zur Folgen haben kann.<br>(3)In den Akten ist zu vermerken, wann die Benachrichtigung ausgehängt und wann sie abgenommen wurde.
= § 307 Anerkenntnis. =
<sup>1</sup>Erkennt eine Partei den gegen sie geltend gemachten Anspruch ganz oder zum Teil an, so ist sie dem Anerkenntnis gemäß zu verurteilen.<sup>2</sup>Einer mündlichen Verhandlung bedarf es insoweit nicht.
= § 309 Erkennende Richter. =
Das Urteil kann nur von denjenigen Richtern gefällt werden, welche der dem Urteil zugrunde liegenden Verhandlungen beigewohnt haben.
= § 589 (ZPO) Zulässigkeitsprüfung =
= § 590 (ZPO) Neue Verhandlung =
= § 591 (ZPO) Rechtsmittel =
:'''Buch 5. Urkunden- und Wechselprozess'''
= § 592 (ZPO) Zulässigkeit. =
1 Ein Anspruch, welcher die Zahlung einer bestimmten Geldsumme oder die Leistung einer bestimmten Menge anderer vertretbarer Sachen oder Wertpapiere zum Gegenstand hat, kann im Urkundenprozess geltend gemacht werden, wenn die sämtlichen zur Begründung des Anspruchs erfolgreichen Tatsachen durch Urkunden bewiesen werden können. 2 Als ein Anspruch, welcher die Zahlung einer Geldsumme zum Gegenstand hat, gilt auch der Anspruch aus einer Hypothek, einer Grundschuld, einer Rentenschuld oder einer Schiffshypothek. '''(Quellinfo = Buch "ZPO" S. 155 ff.)'''
= § 593 (ZPO) Klageinhalt: Urkunden. =
(1) Die Klage muss die Erklärung enthalten, dass im Urkundenprozess geklagt werde. (2) 1 Die Urkunden müssen in Abschrift der Klage oder einem vorbereitenden Schriftsatz beigefügt werden. 2 Im letzteren Fall muss zwischen der Zustellung des Schriftsätze und dem Termin zur mündlichen Verhandlung ein der Einlassungfrist gleicher Zeitraum liegen. '''(Quellinfo = Buch "ZPO" S. 155 ff.)'''
= § 594 (ZPO) (weggefallen) =
'''(Quellinfo = Buch "ZPO" S. 156 ff.)'''
= § 595 (ZPO) Keine Widerklage; Beweismittel. =
(1) Widerklangen sind nicht statthaft. (2) Als Beweismittel sind bezüglich der Echtheit oder Unechtheit einer Urkunde sowie bezüglich anderer als der im § 592 erwähnten Tatsachen nur Urkunden und Antrag auf Parteivernehmung zulässig. (3) Der Urkundenbeweis kann nur durch Vorlegung der Urkunden angetreten werdenden.
'''(Quellinfo = Buch "ZPO" S. 156 ff.)'''
= § 596 (ZPO) Abstehen vom Urkundenprozess. =
Der Kläger kann, ohne dass es der Einwilligiung des Beklagten bedarf, bis zum Schluss der mündlichen Verhandlung von dem Urkundenprozess in der Weise abstehen, dass der Rechtsstreit im ordentlichen Verfahren anhängig bleibt. '''(Quellinfo = Buch "ZPO" S. 156 ff.)'''
= § 597 (ZPO) Klageabweisung =
(1) Insoweit der in der Klage geltend gemachte Anspruch an sich oder infolge einer Einrede des Beklagten als unbegründet sich darstellt, ist der Kläger mit dem Anspruch abzuweisen. (2) Ist der Urkundenprozess unstatthaft, ist insbesondere ein dem Kläger obliegender Beweis nicht mit den im Urkundenprozess zulässigen Beweismitteln angetreten oder mit solchen Beweismitteln nicht vollständig geführt, so wird die Klage als in der gewählten Prozessart unstatthaft abgewiesen, selbst wenn in dem Termin zur mündlichen Verhandlung der Beklagte nicht erschienen ist oder der Klage nur auf Grund von Einwendungen widersprochen hat, die rechtlich unbegründet oder im Urkundenprozess unstatthaft sind. '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
= § 598 (ZPO) Zurückweisung von Einwendungen =
Einwendungen des Beklagten sind, wenn der dem Beklagten obliegende Beweis nicht mit den im Urkundenprozess zulässigen Beweismitteln angetreten oder mit solchen Beweismitteln nicht vollständig geführt ist, als im Urkundenprozess unstatthaft zurückzuweisen. '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
= § 599 (ZPO) Vorbehaltsurteil =
(2) Dem Beklagten, welcher dem geltend gemachten Anspruch widersprochen hat, ist in allen Fällen, in denen er verurteilt wird, die Ausführung seiner Rechte vorzubehalten. (2) Enthält das Urteil keinen Vorbehalt so kann die Ergnuzugn des Urteils nach der Vorschrift des § 321 beantragt werden. (3) Das Urteil, das unter Vorbehalt der Rechte ergeht, ist für die Rechtsmittel und die Zwangsvollstreckung als Endurteil anzusehen. '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
= § 600 (ZPO) Nachverfahren. =
(1) Wird dem Beklagten die Ausführung seiner Rechte vorbehalten, so bleibt der Rechtsstreit im ordentlichen Verfahren anhängig. (2) Soweit sich in diesem Verfahren ergibt, dass der Anspruch des Klägers unbegründet war, gelten die Vorschriften des § 302 Abs. 4 Satz 2 bis 4. (3) Erscheint in diesem Verfahren eine Partei nicht, so sind die Vorschriften über das Versäumnisurteil entsprechend anzuwenden. '''(Quellinfo = Buch "ZPO" S. 156 ff.)'''
= § 601 (ZPO) (weggefallen) =
'''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
= § 602 (ZPO) Wechselprozess. =
Werden im Urkundenprozess Ansprüche aus Wechseln im Sinne des Wechselgesetztes geltend gemacht (Wechselprozess), so sind die nachfolgenden besonderen Vorschriften anzuwenden. '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
::::: '''Buch 6. 1) (aufgehoben)'''
::::: '''§§ 606-687 1) (ZPO) (aufgehoben)'''
::::: '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
= § 603 (ZPO) Gerichtsstand. =
(1) Wechselklagen können sowohl bei dem Gericht des Zahlungsortes als bei dem Gericht angestellt werden, bei dem der Beklagte seinen allgemeinen Gerichtstand hat. (2) Wenn mehrere Wechselverpflichtete gemeinschaftlich verklagt werden, so ist außer dem Gericht des Zahlungsortes das Gericht zuständig, bei dem einer der Beklagten seinen allgemeinen Gerichtstand hat. '''(Quellinfo = Buch "ZPO" S. 17 ff.)'''
= § 604 (ZPO) Klageinhalt: Ladungsfrist. =
(1) Die Klage muss die Erklärung enthalten, dass im Wechselprozess geklagt werde. (2) <sup>1</sup> Die Ladungsfrist beträgt mindestens 24 Stunden , wenn die Ladung an dem Ort, der Sitz des Prozessgerichts ist, zugestellt wird. <sup>2</sup> In Anwaltsprozessen beträgt sie mindestens drei Tage, wenn die Ladung an einem anderen Ort zugestellt wird, der im Bezirk des Prozessgerichts liegt oder von dem ein Teil zu dessen Bezirk gehört. (3) In den höheren Instanzen beträgt die Ladungsfrist mindestens 24 Stunden, wenn die Zustellung der Berufungs- oder Revisionsschrift oder der Ladung an dem Ort erfolgt, der Sitz des höheren Gerichts ist; mindestens drei Tage, wenn die Zustellung an einem anderen Ort erfolgt, der ganz oder zum Teil in dem Landgerichtsbezirk liegt, in dem das höhere Gericht seinen Sitz hat, mindestens eine Woche, wenn die Zustellung sonst im Inland erfolgt. '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
= § 605 (ZPO) Beweisvorschriften. =
(1) Soweit es zur Erhaltung des wechselmäßigen Anspruch der rechtzeitigen Protesterhebung nicht bedarf, ist als Beweismittel bezüglich der Verlegung des Wechsels der Antrag auf Parteivernehmung zulässig. (2) Zur Berücksichtigung der Nebenforderung genügt, dass sie glaubhaft gemacht ist. '''(Quellinfo = Buch "ZPO" S. 158 ff.)'''
= § 605a (ZPO) Scheckprozess =
Werden im Urkundenprozess Ansprüche aus Schecks im Sinne des Scheckgesetzes geltend gemacht (Scheckprozess), so sind die §§ 602 bis 605 entsprechend anzuwenden. '''(Quellinfo = Buch "ZPO" S. 158 ff.)'''
::::: '''Buch 6.''' 1) (aufgehoben)
= §§ 606-687 1) (ZPO) (aufgehoben) =
::::: '''Buch 7. Mahnverfahren'''
= § 688 (ZPO) Zulässigkeit. =
(1) Wegen eines Anspruchs, der die Zahlung einer bestimmten Geldsumme in Euro zum Gegenstand hat, ist auf Antrag des Antragstellers ein Mahnbescheid zu erlassen. (2) Das Mahnverfahren findet nicht statt: <sup>1.</sup> für Ansprüche eines Unternehmers aus einem Vertrag gemäß den §§ 491 bis 508 des Bürgerlichen Gesetzbuchs, wenn der gemäß § 492 Abs. 2 des Gesetzbuchs anzugebende effektive Jahreszins den bei Vertragsschluss geltenden '''Basiszinssatz nach § 247''' des Bürgerlichen Gesetzbuchs um mehr als zwölf Prozentpunkt übersteigt; 2. wenn die Geltendmachung des Anspruch von einer noch nicht erbrachten Gegenleistung abhängig ist; 3. wenn die Zustellung des Mahnbescheids durch öffentliche Bekanntmachung erfolgen müsste. (3) Müsste der Mahnbescheid im Ausland zugestellt werden, findet das Mahnverfahren nur statt, soweit das Anerkennungs- und Vollstreckungsausführungsgesetz vom 19. Februar 2001 (BGB1. I S. 288) dies vorsieht. (4) 1 Die Vorschriften der Verordnung (EG) Nr. 1896/2006 des Europäischen Parlaments und des Rates vom 12. Dezember 2006 zur Einführung eines Europäischen Mahnverfahrens bleiben unberührt. 2 Für die Durchführung gelten die §§1087 bis 1096 '''(Quellinfo = Buch "ZPO" S. 157 ff.)'''
: '''§ 247 (BGB) 1)2) Basiszinssatz.'''(1) 1 Der Basiszinssatz beträgt 3,62 Prozent3). 2 Er verändert sich zum 1.Januar und 1. Juli eines jeden Jahres um die Prozentpunkte, um welche die Bezugsgröße seit der letzten Veränderung des Basiszinssatzes gestiegen oder gefallen ist. 3 Bezugsgröße ist der Zinssatz für die jüngste Hauptrefinanzierungsoperation der Europäischen Zentralbank vor dem ersten Kalendertag des betreffenden Halbjahrs. '''(Quellinfo = Buch "BGB" S. 47 ff.)'''
: 1) Amtl. Anm.L Diese Vorschrift dient der Umsetzung von Artikel 3 der Richtlinie 2000/35/EG des Europäischen Parlaments und des Rates vom 29. Juni 2000 zur Bekämpfung von Zahlungsverzug im Geschäftsverkehr (AB1. EG Nr. L 200 S. 35). Punkte 1-2)='''(Quellinfo = Buch "BGB S. 47 ff.)'''
: 2) Beachte hierzu Übergangsvorschrift in Art. 229 § 7 EGBGB (Nr. 2).
: - ab 1.1.2002 '''2,57%''' (Bek. v. 28.12.2001, BAnz. 2002 Nr. 3 S. 98);
: - ab 1.7.2002 '''2,47%''' (Bek. v. 25.06.2002, BAnz. Nr. 118 S. 14538);
: - ab 1.1.2003 '''1,97%''' (Bek. v. 30.12.2002, BAnz. 2003 Nr.2. S. 76);
: - ab 1.7.2003 '''1,22%''' (Bek. v. 24.06.2003, BAnz. Nr. 117 S. 13744);
: - ab 1.1.2004 '''1,14%''' (Bek. v. 30.12.2003, BAnz. Nr. 2 S. 69);
: - ab 1.7.2004 '''1,13%''' (Bek. v. 29.06.2004, BAnz. Nr. 122 S. 14246);
: - ab 1.1.2005 '''1,21%''' (Bek. v. 30.12.2004, BAnz. Nr. 1 S. 6);
: - ab 1.7.2005 '''1,17%''' (Bek. v. 28.06.2005, BAnz. Nr. 122 S. 10041);
: - ab 1.1.2006 '''1,37%''' (Bek. v. 29.12.2005, BAnz. Nr. 1 S. 2);
: - ab 1.7.2006 '''1,95%''' (Bek. v. 27.06.2006, BAnz. Nr. 191 S. 4754);
: - ab 1.1.2007 '''2,70%''' (Bek. v. 28.12.2006, BAnz. Nr. 245 S. 7463);
: - ab 1.7.2007 '''3,19%'''(Bek. v. 28.06.2007, BAnz. Nr. 117 S. 6530);
: - ab 1.1.2008 '''3,32%''' (Bek. v. 28.12.2007, BAnz. Nr. 242 S. 8415);
: - ab 1.7.2008 '''3,19%''' (Bek. v. 24.06.2008, BAnz. 94 Nr. 1 S. 2232);
: - ab 1.1.2009 '''1,62%''' (Bek. v. 30.12.2008, BAnz. 2009 Nr. 1 S. 6);
: - ab 1.7.2009 '''0,12%''' (Bek. v. 30.06.2009, BAnz. Nr. 95 S. 2302);
: - ab 1.1.2010 '''0,12%''' (Bek. v. 29.12.2009, BAnz. Nr. 198 S. 4582);
: - ab 1.7.2010 '''0,12%''' (Bek. v. 29.06.2010, BAnz.Nr. 96 S. 2264);
: - ab 1.1.2011 '''0,12%''' (Bek. v. 28.12.2010, BAnz. Nr. 199 S. 4388);
: - ab 1.7.2011 '''0,37%''' (Bek. v. 30.06.2011, BAnz. Nr. 96 S. 2314);
: - ab 1.1.2012 '''0,12%''' (Bek. v. 27.12.2011, BAnz. Nr. 197 S. 4659);
: - ab 1.7.2012 '''0,12%''' (Bek. v. 26.06.2012, BAnz. AT 28.06.2012 B3);
: - ab 1.1.2013 '''-0,13%''' (Bek. v. 28.12.2012, BAnz. AT 31.12.2012 B8);
: - ab 1.7.2013 '''-0,38%''' (Bek. v. 25.06.2013, BAnz. AT 27.06.2013 B4);
: - ab 1.1.2014 '''-0,63%''' (Bek. v. 30.12.2013, BAnz. AT 31.12.2013 B7);
: - ab 1.7.2014 '''-0,73%''' (Bek. v. 24.06.2014, BAnz. AT 26.06.2014 B5);
: - ab 1.1.2015 '''-0,83%''' (Bek. v. 30.12.2014, BAnz. AT 31.12.2014 B12);
: - ab 1.7.2015 '''-0,83%''' (Bek. v. 30.06.2015, BAnz. AT 01.07.2015 B6);
: - ab 1.1.2016 '''-0,83%''' (Bek. v. 29.12.2015, BAnz. AT 30.12.2015 B8);
: - ab 1.7.2016 '''-0,88%''' (Bek. v. 28.06.2016, BAnz. AT 29.06.2016 B4);
: - ab 1.1.2017 '''-0,88%''' (Bek. v. 27.12.2016, BAnz. AT 29.12.2016 B11); '''(Quellinfo der aufgeführten Angaben zu den entsprechenden Basiszinssätzen = Buch "BGB" S. 48 ff.)'''
(2) Die Deutsche Bundesbank gibt den geltenden Basiszinssatz unverzüglich nach den in Absatz 1 Satz 2 genannten Zeitpunkten im Bundesanzeiger bekannt. '''(Quellinfo = Buch "BGB" S. 48 ff.)'''
= § 689 (ZPO) Zuständigkeit; maschinelle Bearbeitung. =
(1) 1 Das Mahnverfahren wird von den Amtsgerichten durchgeführt. 2) 2 Eine maschinelle Bearbeitung ist zulässig. 3 Bei dieser Bearbeitung sollen Eingänge spätestens an dem Arbeitstag erledigt sein, der dem Tag des Eingangs folgt. 3 Die Akten können elektronisch geführt werden (§298 a9)
(2) 1 Ausschließlich zuständig ist das Amtsgericht, bei dem der Antragsteller seinen allgemeinen Gerichtsstand hat. 2 Hat der Antragsteller im Inland keinen allgemeinen Gerichtsstand, sonst das Amtsgericht Wedding in Berlin ausschlie´loch zuständig. 3. Sätze 1 und 2 gelten auch, soweit in anderen Vorschriften eine andere ausschließliche Zuständigkeit bestimmt ist.
(3) 1) 1 Die Landesregierungen wären ermächtigt, durch Rechtsverordnung Mahnverfahren einem Amtsgericht für die Bezirke mehrerer Amtsgerichte zuzuweisen, wenn dies ihrer schnelleren und rationelleren Erledigung dient. 2 Die Zuweisung kann auf Mahnverfahren beschränkt werden, die maschinell bearbeitet werden. 3 Die Landesregierungen können die Ermächtigung durch Rechtsverordnung auf die Landesjustizverwaltungen übertragen. 4 Mehrere Länder können die Zuständigkeit eines Amtsgerichts über die Landesgrenzen hinaus vereinbaren. '''(Quellinfo = Buch "ZPO" S. 158 ff.)'''
= § 690 (ZPO) Mahnantrag. =
(1) Der Antrag muss auf den Erlass eines Mahnbescheids gerichtet sein und enthalten: 1. die Bezeichnung der Parteien, ihrer gesetzlichen Vertreter und der Prozessbevollmächtigten; 2. die Bezeichnung des Gerichts, bei dem der Antrag gestellt wird; 3. die Bezeichnung des Anspruchs unter bestimmter Angabe der verlangten Leistung; Haupt - und Nebenforderungen sind gesondert und einzeln zu bezeichnen. Ansprüche aus Verträgen gemäß den '''§§ 491 bis 508 des Bürgerlichen Gesetzbuchs'''; auch unter Angabe des Datums des Vertragsabschlusses und des gemäß '''§ 492 Abs. 2 des Bürgerlichen Gesetzbuchs''' anzugebenden effektiven Jahreszinses; 4. die Erklärung, dass der Anspruch nicht von einer Gegenleistung abhängt oder dass die Gegenleistung erbracht ist; 5. die Bezeichnung des Gerichts, das für ein streitiges Verfahren zuständig ist. (2) Der Antrag bedarf der handschriftlichen Unterzeichnung. (3) 1 Der Antrag kann in einer nur maschinell lesbaren Form vermittelt werden, wenn diese dem Gericht für seine maschinelle Bearbeitung geeignet erscheint. 2 Wird der Antrag von einem Rechtsanwalt oder einer registrierten Person nach § 10 Abs. 1 Satz 1 Nr. 1 des Rechtsdienstleistungegesetztes gestellt, ist nur diese Form der Antragstellung zulässig. '''[Satz 3 ab 1. 1. 2018:]''' 3 Der Antrag kann unter Nutzung des elektronischen Identitätsnachweises nach § 18 des Personalausweisgesetztes oder § 78 Absatz 5 des Aufenthaltsgesetztes gestellt werden. 3 '''[Satz 3 bis 31. 12. 2017, Satz 4 ab 1. 1. 2018 :] Der handschriftlichen Unterzeichnung bedarf es nicht, wenn in anderer Weise gewährleistet ist, dass der Antrag nicht ohne den Willen des Antragstellers übermittelt wird. (Quellinfo = Buch "ZPO" S. 158 ff.)'''
:Kapitel 2 Besondere Vorschriften für Verbraucherdarlehensverträge (BGB)
: '''§ 491 1) 2) Verbraucherdarlehensvertrag.'''
: (1) 1 Die Vorschriften dieses Kapitels gelten für Verbraucherdarlehensverträge, soweit nichts anderes bestimmt ist. 2 Verbraucherdarlehensverträge sind Allgemein- Verbraucherdarlehensverträge und Immobiliar-Verbraucherdarlehensverträge. (2) 1 Allgemein- Verbraucherdarlehensverträge sind entgeltliche Darlehensverträge zwischen einem Unternehmer als Darlehensgeber und einem Verbraucher als Darlehensnehmer. 2 Keine Allgemein Verbraucherdarlehensverträge sind Verträge, 1 bei denen der Nettodarlehensbetrag (Artikel 247 § 3 Abs 2 des Einführungsgesetzes zum Bürgerlichen Gesetzbuche 1) weniger als 200 Euro beträgt. 2 ei denen sich die Haftung des Darlehensnehmers auf eine dem Darlehensgeber zum Pfand übergebene Sache Beschränkt, 3 .bei denen der Darlehensnehmer das Darlehen binnen drei Monaten zurückzuzahlen hat und nur geringe Kosten vereinbart sind. 4. die von Arbeitgebern mit ihren Arbeitnehmers als Nebenleistung zum Arbeitsvertrag zu einem niedrigeren als dem marktüblichen effektiven Jahreszins (§ 6 der Preisangabenverordnung) abgeschlossen werden und anderen Personen nicht angeboten werden. 5. die nur mit einem begrenzten Personenkreis auf Grund von Rechtsvorschriften in öffentlichem Interesse abgeschlossen werden, wenn im Vertrag für den Darlehensnehmer günstigere als marktübliche Bedingungen und höchstens der marktübliche Sollzinssatz vereinbart sind. 6. bei denen es sich um Immobil- Verbraucherdarlehensverträge gemäß Absatz 3 handelt.
: (3) 1 Immobiliar-Verbraucherdarlehendverträge sind entgeltliche Darlehensverträge wischen einem Unternehmer als Darlehensgeber und einem Verbraucher als Darlehensnehmer, die 1. durch ein Grundpfandrecht oder eine Reallast gesichert sind oder 2. für den Erwerb oder die Erhaltung des Eigentumsrechts an Grundstücken, an bestehenden oder zu errichtenden Gebäuden oder für den Erwerb oder die Erhaltung von grundstücksgleichen Rechten bestimmt sind. 2 Keine Immobiliar-Berbraucherdarlehensverträge sind Verträge gemäß Absatz 2 Satz 2 Nummer 4. 3 Auf Immobiliar-Berbruacherdarlehensverträge gemäß Absatz 2 Satz 2 Nummer 4 ist nur '''§ 491 a Absatz 4''' anwendbar. (4) '''§ 358 Abs. 2''' und 4 sowie die '''§§ 491 a bis 495''' und '''505a bis 505 d''' sind nicht auf Darlehensverträge anzuwenden, die in ein nach den Vorschriften der Zivilprozessordnung errichtetes gerichtliches Protokoll aufgenommen oder durch einen gerichtlichen Beschluss über das Zustandekommen und den Inhalt eines zweichen den Parteien geschlossenen Vergleichs festgestellt sind, wenn in das Protokoll oder den Beschluss der Sollzinssatz, die bei Abschluss des Vertrags in Rechnung gestellten Kosten des Darlehens sowie die Voraussetzungen aufgenommen worden sind unter denen der Sollzinssatz oder die Kosten angepasst werden können. '''(Quellinfo = Buch "BGB" S. 117 ff.)'''
= § 691 (ZPO) Zurückweisung des Mahnantrags. =
(1) 1 Der Antrag wird zurückgewiesen: 1. wenn er den Vorschriften der §§ 688, 689,690, 703 c Abs. 2 nicht entspricht; 2. wenn der Mahnbescheid nur wegen eines Teiles des Anspruchs nicht erlassen werden kann. 2 Vor der Zurückweisung ist der Antragsteller zu hören. (2) Sollte durch die Zustellung des Mahnbescheids eine Frist gewahrt werden oder die Verjährung neu beginnen oder nach § 204 des Bürgerlichen Gesetzbuchs gehemmt werden, so tritt die Wirkung mit der Einreichung oder Anbringung des Antrags auf Erlass des Mahnbescheids ein,wenn innerhalb eines Monats seit der Zustellung der Zurückweisung des Antrags Klage eingereicht und diese demnächst zugestellt wird. (3) 1 Gegen die Zurückweisung findet die sofortige Beschwerde statt, wenn der Antrag in einer nur maschinell lesbaren Form übermittelt und mit der Begründung zurückgewiesen worden ist, dass diese Form dem Gericht für seine maschinelle Bearbeitung nicht geeignet erscheine. 2 Im Übrigen sind Entscheidungen nach Absatz 1 unanfechtbar. '''(Quellinfo = Buch "ZPO" S. 159 ff.)'''
= § 692 (ZPO) Mahnbescheid. =
(1) Der Mahnbescheid enthält: 1. die in § 690 Abs. 1 Nr . 1 bis 5 bezeichneten Erfordernisse des Antrags; 2. den Hinweis, dass das Gericht nicht geprüft hat. ob dem Antragsteller der geltend gemachte Anspruch zusteht; 3. die Aufforderung innerhalb von zwei Wochen seit der Zustellung des Mahnbescheids, soweit der geltend gemachte Anspruch als begründet angesehen wird, die behauptete Schuld nebst den geforderten Zinsen und der dem Betrag nach bezeichneten Kosten zu begleichen oder dem Gericht mitzuteilen, ob und in welchem Umfang dem geltend gemachten Anspruch widersprochen wird. 4 den Hinweis, dass ein dem Mahnbescheid entsprechender Vollstreckungsbescheid ergehen kann, aus dem der Antragsteller die Zwangsvollstreckung betreiben kann falls der Antragsgegner nicht bis zum Fristablauf Widerspruch mit jenem Formular der beigefügten Art erhoben hat; 5. für den Fall, dass Formulare eingeführt sind, den Hinweis, dass der Wirderspruch mit jenem Formular der beigefügten Art erhoben werden soll, das auch bei jedem Amtsgericht erhältlich ist und ausgefüllt werden kann; 6. für den Fall des Widerspruchs, die Ankündigung, an welches Gericht die Sache abgegeben wird, mit dem Hinweis, dass diesem Gericht die Prüfung seiner Zuständigkeit vorbehalten bleibt. (2) An Stelle einer handschriftlichen Unterzeichnung genügt ein entsprechender Stempelabdruck oder eine elektronische Signatur. '''(Quellinfo = Buch "ZPO" S. 158 ff.)'''
= § 693 (ZPO) Zustellung des Mahnbescheids. =
(1) Der Mahnbescheid wird dem Antragsgegner zugestellt. (2) Die Geschäftsstelle setzt den Antragsteller on der Zustellung des Mahnbescheids in Kenntnis. '''(Quellinfo = Buch "ZPO" S. 160 ff.)'''
= § 694 (ZPO) Widerspruch gegen den Mahnbescheid. =
(1) Der Antragsgegner kann gegen den Anspruch oder einen Teil des Anspruchs bei dem Gericht, das den Mahnbescheid erlassen hat, schriftlich Widerspruch erheben, solange der Vollstreckungsbescheid nicht verfügt ist. (2) 1 Ein verspäteter Widerspruch wird als Einspruch behandelt. 2 Dies ist dem Antragsgegner, den den Widerspruch erhoben hat, mitzuteilen. '''(Quellinfo = Buch "ZPO" S. 160 ff.)'''
= § 695 (ZPO) Mitteilung des Widerspruchs; Abschriften. =
1 Das Gericht hat den Antragsteller von dem Widerspruch und dem Zeitpunkt seiner Erhebung in Kenntnis zu setzen. 2 Wird das Mahnverfahren nicht maschinell bearbeitet, so soll der Antragsgegner die erforderliche Zahl von Abschriften mit dem Widerspruch einreichen. '''(Quellinfo = Buch "ZPO" S. 160 ff.)'''
= § 696 (ZPO) Verfahren nach Widerspruch. =
(1) 1 Wird rechtzeitig Widerspruch erhoben und beantragt eine Partei die Durchführung des streitigen Verfahrens, so gibt das Gericht, das den Mahnbescheid erlasen hat, den Rechtsstreit von Amts wegen an das Gericht ab, das in dem Mahnbescheid gemäß § 692 Abs. 1 Nr 1 bezeichnet worden ist, wenn die Parteien übereinstimmend die Abgabe an ein anderes Gericht verlangen, an diese. 2 Der Antrag kann in den Antrag auf Erlass des Mahnbescheids aufgenommen werden. 3 Die Abgabe ist den Parteien mitzuteilen; sie ist nicht anfechtbar. 4 Mit Eingang der Akten bei dem Gericht, an das er abgegeben wird, gilt der Rechtstreit als dort anhängig. 5 § 281 Ab. 2 Satz 1 gilt entsprechend. (2) 1 Ist das Mahnverfahren maschinell bearbeitet worden, so tritt, sofern die Akte nicht elektronisch übermittelt wird, an die Stelle der Akten ein maschinell erstellter Aktenausdruck. 2 Für diesen gelten die Vorschriften über die Beweiskraft öffentlicher Urkunden entsprechend. 3 § 298 findet keine Anwendung. (3) Die Streitsache gilt als mit Zustellung des Mahnbescheid rechtshängig geworden, wenn sie alsbald nach de Erhebung des Widerspruch abgegeben wird. (4) 1 Der Antrag auf Durchführung des streitigen Verfahrens kann bis zum Beginn der mündlichen Verhandlung des Antragsgegners zur Hauptsache zurückgenommen werden. 2 Die Zurücknahme kann vor der Geschäftsstelle nicht rechtshängig geworden anzusehen. (5) Das Gericht, an das der Rechtsstreit abgegeben ist, ist hierzu in seiner Zuständigkeit nicht gebunden. '''(Quellinfo = Buch "ZPO" S. 161 ff.)'''
= § 697 (ZPO) Einleitung des Streitverfahrens. =
(1) 1 Die Geschäftsstelle des Gerichts an das die Streitsache abgegeben wird, hat dem Antragsteller unverzüglich aufzugeben, seinem Anspruch binnen zwei Wochen in einer der Klageschrift entsprechende Form zu dd. 2 § 270 Satz 2 gilt entsprechend. (2) 1 Bei Eingang der Anspruchsbegründung ist wie nach Eingang einer Klage weiter zu verfahren. 2 Zur schriftlichen Klageerwiderungen Verfahren. nach § 276 kann auch eine mit der Zustellung der Anspruchsbegründung beginnende Frist gesetzt werden. (3) 1 Geht die Anspruchsbegründung nicht rechtzeitig ein,so wird bis zu ihrem Eingang Termin zur mündlichen mündlichen Verhandlung nur auf Antrag des Antragsgegner bestimmt . 2 Mit der Terminbestimmung setzt der Vorsitzende dem Antragsteller Eine Frist zur Begründung des Anspruchs; § 296 Abs. 1, 4 gilt entsprechend. (4) 1 Der Antragsgegner kann den Widerspruch bis zum Beginn seiner mündlichen Verhandlung zur Hauptsache zurücknehmen, jedoch nicht nach erlass eines Versäumnisurteil s gegen ihn. 2 Die Zurücknahme kann zu Protokoll der Geschäftsstelle erklärt werden. (5) 1 Zur Herstellung eines Urteils in abgekürzter Form nach § 313 b Ansatz 2, § 317 Absatz 6 kann der Mahnbecheid an Stelle der Klageschrift benutzt werden . 2 Ist das Mahnverfahren maschinell bearbeitet worden, so tritt an die Stelle der Klageschrift der maschinell erstellte Aktenausdruck. '''(Quellinfo = Buch "ZPO" S. 130 ff.)'''
= § 698 (ZPO) Abgabe des Verfahrens am selben Gericht. =
Die Vorschriften über die Abgabe des Verfahrens gelten sinngemäß, wenn Mahnverfahren und streitiges Verfahren bei demselben Gericht durchgeführt werden. '''(Quellinfo = Buch "ZPO" S. 130 ff.)'''
= § 699 (ZPO) Vollstreckungsbescheid. =
(1) 1 Auf der Grundlage des Mahnbescheids erlässt das Gericht auf Antrag einen Vollstreckungsbescheid, wenn der Antragsgegner nicht rechtzeitig Widerspruch erhoben hat. 2 Der Antrag kann nicht vor Ablauf der Widerspruchsfrist gestellt werden; er hat die Erklärung zu enthalten, ob und welche Zahlungen auf den Bescheid geleistet worden sind; '''[bis 31. 12. 2017:''' § 690 Abs. 3 Satz 1 und 3''']''' '''[ab 1. 1. 2018:''' § 690 Abs. 3''']''' gilt entsprechend 3 Ist der Rechtsstreit bereits an ein anderes Gericht abgegeben, so erlässt dieses den Vollstreckungsbescheid. (2) Soweit das Mahnverfahren nicht maschinell bearbeitet wird kann der Vollstreckungsbescheid auf den Mahnbescheid gesetzt werden. (3) 1 In den Vollstreckungsbescheid sind die bisher entstandenen Kosten des Verfahrens aufzunehmen. 2 Der Antragsteller braucht die Kosten nur zu berechnen,, wenn das Mahnverfahren nicht maschinell bearbeitet wird; im Übrigen genügen die zur maschinellen Berechnung erforderlichen Angaben. (4) 1 Der Vollstreckungsbescheid wird dem Antragsgegner von Amts wegen zugestellt, wenn nicht der Antragsteller die Übermittlung an sich zur Zustellung im Parteibetrieb beantragt hat. 2 In diesen Fällen wird der Vollstreckungsbescheid dem Antragsteller zur Zustellung übermittelt; die Geschäftsstelle des Gerichts vermittelt diese Zustellung nicht. 3 Bewilligt das mit dem Mahnverfahren befasste Gericht die öffentliche Zustellung, so wird die Benachrichtigung nach § 186 Abs 2 Satz 2 und an die Gerichtstagel des Gerichts angeheftet oder in das Informationssystem des Gerichts eingestellt, das in dem Mahnbescheid gemäß § 692 Abs 1 Nr. 1 bezeichnet worden ist. (5) Die Belehrung gemäß § 232 ist dem Antragsgegner zusammen mit der Zustellung des Vollsreckungsbescheids schriftlich mitzuteilen. '''(Quellinfo = Buch "ZPO" S. 161 ff.)'''
= § 700 (ZPO) Einspruch gegen den Vollstreckungsbescheid. =
(1) Der Vollstreckungsbescheid steht einem für vorläufig vollstreckbar erklärten Versäumnisurteil gleich. (2) Die Streitsache gilt als mit der Zustellung des Mahnbescheids rechtshängig geworden. (3) 1 Wird Einspruch eingelegt, so gibt das Gericht, das den Vollstreckungsbescheid erlassen hat, den Rechtsstreit von Amts wegen an das Gericht ab, das in dem Mahnbescheid gemäß § 692 Abs. 1 Nr. 1 bezeichnet worden ist, wenn die Parteien übereinstimmend die Abgabe an ein anderes Gericht verlangen, an dieses. 2. §696 Abs. 1 Satz 3 bis 5, Abs2, 5 § 697 Abs. 1, 4, § 698 gelten entsprechend. 3 § 340 Abs. 3 ist nicht anzuwenden. (4) 1 Bei Eingang Teer Anspruchsbegründung ist wie nach Eingang einer Klage weiter zu verfahren wenn der Einspruch nicht als unzulässig verworfen wird. 2 § 276 Abs. 1 Satz 1 3 , Abs. 2 ist nicht anzuwenden. (5) Geht die Anspruchsbegründung innerhalb der von der Geschäftsstelle gesetzten Frist nicht ein und wird der Einspruch auch nicht als unzulässig verworfen, bestimmt der Vorsitzende unverzüglich Termin; § 697 Abs. 3 Satz 2 gilt entsprechend. (6) Der Einspruch darf nach § 345 nur verworfen werden, soweit der Voraussetzungen des § 331 Abs 1,2 erster Halbsatz fr ein Versäumnisurteil vorliegen, wird der Vollstreckungsbescheid aufgeben. '''(Quellinfo = Buch "ZPO" S. 162 ff.)'''
= § 701 (ZPO) Wegfall der Wirkung des Mahnbescheids. =
1 Ist Widerspruch nicht erhoben und beantragt der Antragsteller den Erlass des Vollstreckungsbescheids nicht binnen einer sechsmonatigen Frist, die mit der Zustellung des Mahnbescheids beginnt, so fällt die Wirkung des Mahnbescheids weg. 2 Dasselbe gilt, wenn der Vollstreckungsbescheid rechtzeitig beantragt ist, der Antrag aber zurückgewiesen wird. '''(Quellinfo = Buch "ZPO" S. 163 ff.)'''
= § 702 (ZPO) Form von Anträgen und Erklärungen. =
(1) 1 Im Mahnverfahren können die Anträge und Erklärungen vor dem Urkundsbeamten der Geschäftsstelle abgegeben werden. 2 Soweit Formulare eingeführt sind, werden diese ausgefüllt; der Urkundsbeamte vermerkt unter Angabe des Gerichts und des Datums, dass er den Antrag oder die Erklärung aufgenommen hat. 3 Auch soweit Formulare nicht eingeführt sind, ist für den Antrag auf Erlass eines Mahnbescheids oder eines Vollsstreckungsbescheids bei dem für das Mahnverfahren zuständigen Gericht die Aufnahme eines Protokolls nicht erforderlich. (2) Der Antrag auf Erlass eines Mahnbesheids oder eines Vollstreckungsbescheids wir dem Antragsgegner nicht mitgeteilt. '''(Quellinfo = Buch "ZPO" S. 163 ff.)'''
= § 703 (ZPO) Kein Nachweis der Vollmacht. =
1 Im Mahnverfahren bedarf es des Nachweises einer Vollmacht nicht. 2 Wer als Bevollmächtigter einen Antrag einreicht oder einen Rechtsbehelf einlegt, hat seine ordnungsgemäße Bevollmächtigung zu versichern. '''(Quellinfo = Buch "ZPO" S. 163 ff.)'''
= § 703 a (ZPO) Urkunden-, Wechsel- und Scheckmahnverfahren. =
(1) Ist der Antrag des Antragstellers auf den Erlass eines Urkunden- Wechsel- oder Scheckmahnbescheids gerichtet, so wird der Mahnbescheid als Urkunden-, Wechsel- oder Scheckmahnbescheid bezeichnet. (2) Für das Urkunden-, Wechsel- und Scheckmahnverfahren gelten folgende besondere Vorschriften: 1. die Bezeichnung als Urkunden-, Wechsel- oder Scheckmahnbescheid hat die Wirkung, dass die Streitsache, wenn rechtzeitig Widerspruch erhoben wird, im Urkunden-, Wechsel- oder Scheckprozess anhängig wird, 2. die Urkunden sollen in dem Antrag auf Erlass des Mahnbescheids und in dem Mahnbescheid bezeichnet werden; ist die Sache an das Streitgericht abzugeben, so müssen die Urkunden in Urschrift oder in Abschrift der Anspruchsbegründung beigefügt werden; 3. im Mahnverfahren ist nicht zu prüfen, ob die gewählte Prozessart statthaft ist. 4. beschränkt sich der Widerspruch auf den Antrag, dem Beklagten die Ausführung seiner Rechte vorzubehalten, so ist der Vollstreckungsbescheid unter diesen Vorbehalt zu erlassen. Auf das weitere Verfahren ist die Vorschrift des § 600 entsprechend anzuwenden. '''(Quellinfo = Buch "ZPO" S. 163 ff.)'''
= § 703 b (ZPO) Sonderregelungen für maschinelle Bearbeitung. =
(1) Bei maschineller Bearbeitung werden Beschlüsse, Verfügungen, Ausfertigungen und Vollstreckungsklauseln mit dem Gerichtssiegel versehen; einer Unterschrift bedarf es nicht. (2) Das Bundesministerium der Justiz und für Verbraucherschutz wird ermächtigt, durch Rechtsverordnung mit Zustimmung des Bundesrates den Verfahrensablauf zu regeln, soweit dies für eine einheitliche maschinelle Bearbeitung der Mahnverfahren erforderlich ist (Verfahrensablaufplan) '''(Quellinfo = Buch "ZPO" S. 163 ff.)'''
= § 703 c (ZPO) Formulare; Einführung der maschinellen Bearbeitung. =
(1) 1 Das Bundesministerium der Justiz und für Verbraucherschutz wird ermächtigt, durch Rechtsverordnung 1) mit Zustimmung des Bundesrates zur Vereinfachung des Mahnverfahrens und zum Schutze der in Anspruch genommenen Partei Formulare einzuführen. 2 Für 1. Mahnverfahren bei Gerichten, die die Verfahren maschinell bearbeiten. 2. Mahnverfahren bei Gerichten, die die Verfahren nicht maschinell bearbeiten. 3. Mahnerfahren, in denen der Mahnbescheid im Ausland zuzustellen ist. 4. Mahnverfahren, in denen der Mahnbescheid nach Artikel 32 des Zusatzabkommen zum NATO-Truppenstatut vom 3. August 1959 (BGB1, 1961 II S. 1183, 1218) zuzustellen ist, können unterschiedliche Formulare eingeführt werden. (2) Soweit nach Absatz 1 Formulare für Anträge und Erklärungen der Parteien eingeführt sind, müssen sich die Parteien ihrer bedienen. (3) Die Landesregierungen bestimmen durch Rechtsverordnung den Zeitpunkt, in dem bei einem Amtsgericht maschinelle Bearbeitung der Mahnverfahren eingeführt wird; sie können die Ermächtigung durch Rechtsverordnung auf die Landesjustizverwaltungen übertragen. '''(Quellinfo = Buch "ZPO" S. 164 ff.)'''
= § 703 d (ZPO) Antragsgegner ohne allgemeinen inländischen Gerichtsstand. =
(1) Hat der Antragsgegner keinen allgemeinen Gerichtsstand im Inland, so gelten die nachfolgenden besonderen Vorschriften. (2) 1 Zuständig für das Mahnverfahren ist das Amtsgericht, das für das streitige Verfahren zuständig sein würde, wenn die Amtsgerichte im ersten Rechtszug sachlich unbeschränkt zuständig wären. 2 § 689 Abs. 2 gilt entsprechend. '''(Quellinfo = Buch "ZPO" S. 164 ff.)'''
::'''Buch 8. Zwangsvollstreckung'''
: '''Abschnitt 1. Allgemeine Vorschriften'''
= § 704 (ZPO) Vollstreckbare Endurteile. =
Die Zwangsvollstreckung findet statt aus Endurteilen, die rechtskräftig oder für vorläufig vollstreckbar erklärt sind. '''(Quellinfo = Buch "ZPO" S. 164 ff.)'''
= § 705 (ZPO) Formelle Rechtskraft. =
1 Die Rechtskraft der Urteile tritt vor Ablauf der für die Einlegung des zulässigen Rechtsmittels oder des zulässigen Einspruchs bestimmten Frist nicht ein. 2 Der Einritt der Rechtskraft wird durch rechtzeitige Einlegung des Rechtsmittels oder des Einspruchs gehemmt. '''(Quellinfo = Buch "ZPO" S. 165 ff.)'''
= § 706 (ZPO) Rechtskraft- und Notfristzeugnis. =
(1) Zeugnisse über die Rechtskraft der Urteile sind auf Grund der Prozessakten von der Geschäftsstelle des Gerichts des ersten Rechtszuges und, solange der Rechtsstreit in einem höheren Rechtszug anhängig ist, von der Geschäftsstelle des Gerichts dieses Rechtszuges zu erteilen. (2) 1 Soweit die Erteilung des Zeugnisses davon abhängt, dass gegen das Urteil ein Rechtsmittel nicht eingelegt ist, holt die Geschäftsstelle des Gerichts des ersten Rechtszuges bei der Geschäftsstelle des für das Rechtsmittel zuständigen Gerichts eine Mitteilung in Textform ein, dass bis zum Ablauf der Notfrist eine Rechtsmittelschrift nicht eingereicht sei. 2 Einer Mitteilung durch die Geschäftsstelle des Revisonsgerichts, dass ein Antrag auf Zulassung der Revision nach § 566 nicht eingereicht sei, bedarf es nicht. '''(Quellinfo = Buch "ZPO" S. 165 ff.)'''
= § 707 (ZPO) Einstweilige Einstellung der Zwangsvollstreckung. =
(1) 1 Wird die Wiedereinsetzung in den vorigen Stand oder eine Wiederaufnahme des Verfahrens beantragt oder die Rüge nach § 321 a erhoben oder wird der Rechtsstreit nach der Verkündung eines Vorbehaltsurteils fortgesetzt , so kann das Gericht auf Antrag anordnen, dass die Zwangsvollstreckung gegen oder ohne Sicherheitsleistung einstweilen eingestellt werde oder nur gegen Sicherheitsleistung stattfinde und dass die Vollstreckungsmaßregeln gegen Sicherheitsleistung aufzuheben seien. 2 Die Einstellung der Zwangsvollstreckung ohne Sicherheitsleistung ist nur zulässig, wenn glaubhaft gemacht wird, dass der Schuldner zur Sicherheitsleistung nicht in der Lage ist und die Vollstreckung einen nicht zu ersetzenden Nachteil bringen würde. (2) 1 Die Entscheidung ergeht durch Beschluss. 2 Eine Anfechtung des Beschlusses findet nicht statt. '''(Quellinfo = Buch "ZPO" S. 165 ff.)'''
= § 708 (ZPO) Vorläufige Vollstreckbarkeit ohne Sicherheitsleistung. =
Für vorläufig vollstreckbar ohne Sicherheitsleistung sind zu erklären: 1. Urteile, die auf Grund eines Anerkenntnissen oder eines Verzichts ergehen; 2. Versäumnisurteile und Urteile nach Lage der Akten gegen die säumige Partei gemäß § 331 a; 3. Urteile, durch die gemäß § 341 der Einspruch als unzulässig verworfen wird; 4. Urteile, die im Urkunden-, Wechsel- oder Scheckprozess erlassen werden; 5. Urteile, die ein Vorbehaltsurteil, das im Urkunden-, Wechsel- oder Scheckprozess erlassen wurde, für vorbehaltlos erklären; 6. Urteile, durch die Arreste oder einstweilige Verfügungen abgelehnt oder aufgehoben werden 7. Urteile in Streitigkeiten zwischen dem Vermieter und dem Mieter oder Untermieter von Wohnräumen oder anderen Räumen oder zwischen dem Mieder und dem Untermieter solcher Räume wegen Überlassung, Benutzung oder Räumung, wegen Fortsetzung des Mietverhältnisses über Wohnraum auf Grund der §§ 574 bis 574 b des Bürgerlichen Gesetzbuchs sowie wegen Zurückhaltung der von dem Mieter oder dem Untermieter in die Mieträume eingebrachten Sachen; 8. Urteile, die die Verpflichtung aussprechen, Unterhalt, Renten wegen Entziehung einer Unterhaltsforderung oder Renten wegen einer Verletzung des Körpers oder der Gesundheit zu entrichten soweit sich die Verpflichtung auf die Zeit nach der Klageerhebung und auf das ihr vorausgehende letzte Vierteljahr erzieht; 9. Urteile nach §§ 861, 862 des Bürgerlichen Gesetzbuchs auf Wiedereinräumung des Besitzes oder auf Beseitigung oder Unterlassung einer Besitzstörung; 10. Berufungsurteile in vermögensrechtlichen Streitigkeiten. Wird die Berufung durch Urteil oder Beschluss gemäß § 522 Absatz 2 zurückgewiesen., ist auszusprechen dass das angefochtene Urteil ohne Sicherheitsleistung vorläufig vollstreckbar ist; 11. andere Urteile in vermögensrechtlichen Streitigkeiten, wenn der Gegenstand der Verurteilung in der Hauptsache 1250 Euro nicht übersteigt oder wenn nur die Entscheidung über die Kosten vollstreckbar ist und eine Vollstreckung im Wert von nicht mehr als 1500 Euro ermöglicht. '''(Quellinfo = Buch "ZPO" S. 165 ff.)'''
= § 709 (ZPO) Vorläufige Vollstreckbarkeit gegen Sicherheitsleistung. =
1 Andere Urteile sind gegen eine der Höhe nach zu bestimmende Sicherheit für vorläufig vollstreckbar zu erklären. 2 Soweit wegen einer Geldforderung zu vollstrecken ist, genügt es, wenn die Höhe der Sicherheitsleistung in einem bestimmten Verhältnis zur Höhe des jeweils zu vollstreckenden Betrages angegeben wird. 3 Handelt es sich um ein Urteil, das ein Versäumnisurteil aufrechterhält, so ist auszusprechen, dass die Vollstreckung aus dem Versäumnisurteil nur gegen Leistung oder Sicherheit fortgesetzt werden darf. '''(Quellinfo = Buch "ZPO" S. 166 ff.)'''
= § 710 (ZPO) Ausnahmen von der Sicherheitsleistung des Gläubigers. =
Kann der Gläubiger die Sicherheit nach § 709 nicht oder nur unter erheblichen Schwierigkeiten leisten, so ist das Urteil auf Antrag auch ohne Sicherheitsleistung für vorläufig vollstreckbar zu erklären, wenn die Aussetzung der Vollstreckung dem Gläubiger einen schwer zu ersetzenden oder schwer abzusehenden Nachteil bringen würde oder aus einem sonstigen Grund für den Gläubiger unbillig wäre, insbesondere weil der die Leistung für seine Lebenshaltung oder seine Erwerbstätigkeit dringend benötigt. '''(Quellinfo = Buch "ZPO" S. 166 ff.)'''
= § 711 (ZPO) Abwendungsbefugnis. =
1 In den Fällen des § 708 Nr. 4 bis 11 hat das Gericht auszusprechen, dass der Schuldner die Vollstreckung durch Sicherheitsleistung oder Hinterlegung abwenden darf, wenn nicht der Gläubiger vor der Vollstreckung Sicherheit leistet. 2 § 709 Satz 2 gilt entsprechend, für den Schuldner jedoch mit der Maßgabe dass Sicherheit in einem bestimmten Verhältnis zur Höhe des auf Grund des Urteils vollstreckbaren Betrages zu leisten ist. 3 Für den Gläubiger gilt § 710 entsprechend. '''(Quellinfo = Buch "ZPO" S. 166 ff.)'''
= § 712 (ZPO) Schutzantrag des Schuldners. =
(1) 1 Würde die Vollstreckung dem Schuldner einen nicht zu ersetzenden Nachteil bringen, so hat ihm das Gericht auf Antrag zu gestatten, die Vollstreckung durch Sicherheitsleistung oder Hinterlegung ohne Rücksicht auf eine Sicherheitsleistung des Gläubigers abzuwenden; § 709 Satz 2 gilt in den Fällen des § 709 Satz 1 entsprechend. 2 Ist der Schuldner dazu nicht in der Lage, so ist das Urteil nicht für vorläufig vollstreckbar zu erklären oder die Vollstreckung auf die in § 720a Abs. 1, 2 bezeichneten Maßregeln zu beschränken. (2) 1 Dem Antrag des Schuldners ist nicht zu entsprechen wenn ein überwiegendes Interesse des Gläubigers entgegensteht. 2 In den Fällen des § 708 kann das Gericht anordnen, dass das Urteil nur gegen Sicherheitsleistung vorläufig vollstreckbar ist. '''(Quellinfo = Buch "ZPO" S. 167 ff.)'''
= § 713 (ZPO) Unterbleiben von Schuldnerschutzanordnungen. =
Die in den §§ 711, 712 zugunsten des Schuldners zugelassenen Anordnungen sollen nicht ergehen, wen die Voraussetzungen, unter denen ein Rechtsmittel gegen das Urteil stattfindet, unzweifelhaft nicht vorliegen. '''(Quellinfo = Buch "ZPO" S. 168 ff.)'''
= § 714 (ZPO) Anträge zur vorläufigen Vollstreckbarkeit. =
(1) Anträge nach den §§ 710, 711 Satz 3, § 712 sind vor Schluss der mündlichen Verhandlung zu stellen, auf die das Urteil ergeht. (2) Die tatsächlichen Voraussetzungen sind glaubhaft zu machen. '''(Quellinfo = Buch "ZPO" S. 168 ff.)'''
= § 715 (ZPO) Rückgabe der Sicherheit. =
(1) 1 Das Gericht, das eine Sicherheitsleistung des Gläubigers angeordnet oder zugelassen hat, ordnet auf Antrag die Rückgabe der Sicherheit an, wenn ein Zeugnis über die Rechtskraft des für vorläufig vollstreckbar erklärten Urteils vorgelegt wird. 2 Ist die Sicherheit durch eine Bürgschaft bewirkt worden, so ordnet das Gericht das Erlöschen der Bürgschaft an. (2) § 109 Abs. 3 gilt entsprechend. '''(Quellinfo = Buch "ZPO" S. 168 ff.)'''
= § 716 (ZPO) Ergänzung des Urteils. =
Ist über die vorläufige Vollstrecktbarkeit nicht entschieden, so sind wegen Ergänzung des Urteils die Vorschriften des § 321 anzuwenden. '''(Quellinfo = Buch "ZPO" S. 168 ff.)'''
= § 717 (ZPO) Wirkungen eines aufhebenden oder abändernden Urteils =
(1) Die vorläufige Vollstreckbarkeit tritt mit der Verkündung eines Urteils, das die Entscheidung In der Hauptsache oder die Vollsteckbarkeitserklärung aufhebt oder abändert, insoweit außer Kraft, als die Aufhebung oder Abänderung ergeht. (2) 1 Wird ein für vorläufig vollstreckbar erklärtes Urteil aufgehoben oder abgeändert, so ist der Kläger zum Ersatz des Schadens verpflichtet, der dem Beklagten durch die Vollstreckung des Urteils oder durch eine zur Abwendung der Vollstreckung gemachte Leistung entstanden ist. 2 Der Beklagte kann den Anspruch auf Schadensersatz in dem anhängigen Rechtsstreit geltend machen, wird der Anspruch geltend gemacht, so ist er als zur Zeit der Zahlung oder Leistung rechtshängig geworden anzusehen. (3) 1 Die Vorschriften des Absatzes 2 sind auf die im § 708 Nr. 10 bezeichneten Berufungsurteile mit Ausnahme der Versäumnisurteile, nicht anzuwenden. 2 Soweit ein solches Urteil aufgehoben oder abgeändert wird, ist der Kläger auf Antrag des Beklagten zur Erstattung des von diesem auf Grund des Urteils Gezahlten oder Geleisteten zu verurteilen. 3 Die Erstattungspflicht des Klägers bestimmt sich nach den Vorschriften über die Herausgabe einer ungerechtfertigten Bereicherung. 4. Wird der Antrag gestellt, so ist der Anspruch auf Erstattung als zur Zeit der Zahlung oder Leistung rechtshängig geworden anzusehen: die mit der Rechtsabhängigkeit nach den Vorschriften des bürgerlichen Rechts verbundenen Wirkungen treten mit der Zahlung oder Leistung auch dann ein, wenn der Antrag nicht gestellt wird.'''(Quellinfo = Buch "ZPO" S. 168 ff.)'''
= § 718 (ZPO) Vorabentscheidung über vorläufige Vollstreckbarkeit =
(1) In der Berufungsinstanz ist über die vorläufige Vollstreckbarkeit auf Antrag vorab zu verhandeln und zu entscheiden, (2) Eine Anfechtung der in der Berufungsinstanz über die vorläufige Vollstreckbarkeit erlassenen Entscheidung findet nicht statt. '''(Quellinfo = Buch "ZPO" S. 169 ff.)'''
= § 719 (ZPO) Einstweilige Einstellung bei Rechtsmittel und Einspruch. =
(1) 1 Wird gegen ein für vorläufig vollstreckbar erklärtes Urteil der Einspruch oder die Berufung eingelegt, so gelten die Vorschriften des § 707 entsprechend. 2 Die Zwangsvollstreckung aus einem Versäumnisurteil darf nur gegen Sicherheitsleistung eingestellt werden, es sei denn, dass das Versäumnisurteil nicht in gesetzlicher Weise ergangen ist oder sie säumige Partei glaubhaft macht, dass ihr Säumnis unverschuldet war.
(2) 1 Wird Revision gegen ein für vorläufig vollstreckbar erklärtes Urteil eingelegt, so ordnet das Revisionsgericht auf Antrag an, dass die Zwangsvollstreckung einstweilen eingestellt wird, wenn die Vollstreckung dem Schuldner einen nicht zu ersetzenden Nachteil bringen würde und nicht ein überwiegendes Interesse des Gläubigers entgegensteht. 2 Die Parteien haben die tatsächlichen Voraussetzungen glaubhaft zu machen.
(3) Die Entscheidung ergeht per Beschluss. '''(Quellinfo = Buch "ZPO" S. 169 ff.)'''
= § 720 (ZPO) Hinterlegung bei Abwendung der Vollstreckung. =
Darf der Schuldner nach § 711 Abs. 1 Satz 1 die Vollstreckung durch Sicherheitsleistung oder Hinterlegung abwenden, so ist gepfändetes Geld oder der Erlös gepfändeter Gegenstände zu hinterlegen.
= § 721 (ZPO) Räumungsfrist. =
.....Text folgt noch!
= § 722 (ZPO) Vollstreckbarkeit ausländischer Urteile. =
.....Text folgt noch!
= § 723 (ZPO) Vollstreckungsurteil. =
.....Text folgt noch!
= § 724 (ZPO) Vollstreckbare Ausfertigung. =
.....Text folgt noch!
= § 725 (ZPO) Vollstreckungsklausel. =
.....Text folgt noch!
= § 726 (ZPO) Vollstreckbare Ausfertigung bei bedingten Leistungen. =
.....Text folgt noch!
= § 727 (ZPO) Vollstreckbare Ausfertigung für und gegen Rechtsnachfolger. =
.....Text folgt noch!
= § 728 (ZPO) Vollstreckbare Ausfertigung bei Nacherbe oder Testamentsvollstrecker. =
.....Text folgt noch!
= § 729 (ZPO) Vollstreckbare Ausfertigung gegen Vermögens- und Firmenübernehmer. =
.....Text folgt noch!
= § 730 (ZPO) Anhörung des Schuldners. =
.....Text folgt noch!
= § 731 (ZPO) Klage auf Erteilung der Vollstreckungsklausel. =
.....Text folgt noch!
= § 755<sup>1)</sup>Ermittlung des Aufenthaltsorts des Schuldners. =
(1) <sup>1</sup> Ist der Wohnsitz oder gewöhnliche Aufenhaltsort des Schuldners nicht bekannt, darf der Gerichtsvollzieher auf Grund des Vollstreckungsauftrags und der Übergabe der vollstreckbaren Ausfertigung zur Ermittlung des Aufenthaltsorts des Schuldners bei der Meldebehörde die gegenwärtigen Anschriften sowie Angaben zur Haupt- und Nebenwohnung des Schuldners erheben.
<sup>2</sup>Der Gerichtsvollzieher darf auch beauftragt werden, die gegenwärtigen Anschriften, den Ort der Hauptniederlassung oder den Sitz des Schuldners zu erheben. Ort der Hauptniederlassung öden den Sitz des Schuldners zu erheben. <br> 1. durch Einsicht in das Handels-, Genossenschaft-, Partnerschafts-, Unternehmens- oder Vereinsregister oder <br> 2. durch Einholung einer Auskunft bei den nach Landesrecht für die Durchführung der Aufgaben nach § 14 Absatz 1 der Gewerbeordnung zuständigen Behörden.
(2)<sup>1</sup>Soweit der Aufenthaltsort des Schuldners nach Absatz 1 nicht zu ermitteln ist, darf der Gerichtsvollzieher <br> 1. zunächst beim Ausländerzentralregisteer die Angaben zur aktenführenden Ausländerbehörde sowie zum Zuzug oder Fortzug des Schuldners und anschließend bei der gemäß der Auskunft aus dem Ausländerzentralregister aktenführenden Ausländerbehörde den Aufenthaltsort des Schuldners. <br> 2. bei den Trägern der gesetzlichen Rentenversicherung '''''[ab 1.1.2022: '' '''''und bei einer berufsständischen Versorgungseinrichtung im Sinne des § 6 Absatz 1 Satz 1 Nummer 1 des Sechsten Buches Sozialgesetzbuch]'' die dort bekannte derzeitige Anschrift, den derzeitigen oder zukünftigen Aufenthaltsort des Schulders sowie''' <br> '''3. bei dem Kraftfahrt-Bundesamt die Halterdaten nach § 33 Abs. 1 Satz 1 Nr. 2 des Straßenverkehrsgesetzes erheben.''' <sup>2</sup>'''Ist der Schuldner Unionsbürger, darf der Gerichtsvollzieher die Daten nach Satz 1 Nummer 1 nur erheben, wenn ihm tatsächliche Anhaltspunkte für die Vermutung der Feststellung des Nichtbestehens oder des Verlusts des Freizügigkeitsrechts vorliegen'''. <sup>3</sup>'''Eine Übermittlungen Daten nach Satz 1 Nummer 1 an den Gerichtsvollzieher ist ausgeschlossen, wenn der Schuldner Unionsbürger ist, für den eine Feststellung des Nichtbestehens oder des Verlusts des Freizügigkeitsrechts nicht vorliegt. '''''[Satz 4 ab 1.1.2022:]''''' <sup>4</sup>Die ''Erhebung nach Satz 1 Nummer 2 bei einer berufsständischen Versorgungseinrichtung darf der Gerichtsvollzieher nurdurchführen, wenn der Gläubiger die berufsständische Versorgungseinrichtung bezeichnet und tatsächliche Anhaltspunkte nennt, die nahelegen, dass der Schuldner Mitglied dieser berufsständischen Versorgungseinrichtung ist.'' <br> (3) Nach Absatz 1 oder Absatz 2 erhobene Daten, die innerhalb der letzten drei Monate bei dem Gerichtsvollzieher eingegangensind, darf dieser auch in einem Zwangsvollstreckungsverfahren eines weiteren Gläubigers gegen denselben Schuldner verarbeiten, wenn die Voraussetzungen für die Datenerhebung auch bei diesem Gläubiger vorliegen.
= § 758 (ZPO) Durchsuchung: Gewaltanwendung. =
(1) Der Gerichtsvollzieher ist befugt, die Wohnung und die Behältnisse des Schuldners zu durchsuchen, soweit der Zweck der Vollstreckung dies erfordert. (2) Er ist befugt, die verschlossenen Haustüren, Zimmertüren und Behältnisse öffnen zu lassen. (3) Er ist, wenn er Widerstand findet, zur Anwendung von Gewalt befugt und kann zu diesem Zweck die Unterstützung der polizeilichen Vollzugsorgane nachsuchen. '''(Quellinfo = Buch "ZPO" S. 177 ff.)'''
= § 758a (ZPO) Richterliche Durchsuchungsanordnung: Vollstreckung zur Unzeit =
(1) 1 Die Wohnung des Schuldners darf ohne dessen Einwilligung nur auf Grund einer Anordnung des Richters bei dem Amtsgericht durchsucht werden, in dessen Bezirk die Durchsuchung erfolgen soll. 2 Dies gilt nicht, wenn die Einholung der Anordnung den Erfolg der Durchsuchung gefährden würde.
(2) Auf die Vollstreckung eines Titels auf Räumung oder Herausgabe von Räumen und auf die Vollstreckung eines Haftbefehls nach § 802g ist Absatz 1 nicht anzuwenden. (3) 1 Willigt der Schuldner in die Durchsuchung ein oder ist eine Anordnung gegen ihn nach Absatz 1 Satz 1 ergangen oder nach Absatz 1 Satz 2 entbehrlich, so haben Personen die Mitgewahrsam an der Wohnung des Schuldner haben, die Durchsuchung zu dulden. 2 Unbillige Härten gegenüber Mitgewahrsamsinhabern sind zu vermeiden. (4) 1 Der Gerichtsvollzieher nimmt eine Vollstreckungshandlung zur Nachtzeit und an Sonn- und Feiertagen nicht vor, wenn dies für den Schuldner und die Mitgewahrsamtsinhaber eine unbillige Härte darstellt oder der zu erwartende Erfolg in einem Missverhältnis zu dem Eingriff steht, in Wohnungen nur auf Grund einer besondreren Anordnung des Richters bei dem Amtsgericht. 2 Die Nachtzeit umfasst die Stunden von 21 bis 6 Uhr. (5) Die Anordnung nach Absatz 1 ist bei der Zwangsvollstreckung vorzuzeigen. (6) 1 Das Bundesministerium der Justiz und für Verbraucherschutz wird ermächtigt durch Rechtsverordnung mit Zustimmung des Bundesrates Formulare für den Antrag auf Erlass einer richterlichen Durchsungsanordnung nach Absatz 1 einzuführen. 2 Soweit nach Satz 1 Formulare eingeführt sind, muss sich der Antragsteller ihrer bedienen. 3 Für Verfahren bei Gerichten die die Verfahren elektronisch bearbeiten und für Verfahren bei Gerichten, die die Verfahren nichtelektronisch bearbeiten, können unterschiedlichen Formulare eingeführt werden. '''(Quellinfo = Buch "ZPO" S. 177 ff.)'''
= § 759 (ZPO) Zuziehung von Zeugen =
Wird bei einer Vollstreckungshandlung Widerstand geleistet oder ist bei einer in der Wohnung des Schuldners vorzunehmenden Vollstreckungshandlung weder der Schuldner noch ein erwachsener Familienangehöriger, eine in der Familie beschäftigte Person oder ein erwachsener ständiger Mitbewohner anwesend, so hat der Gerichtsvollzieher zwei erwachsener Personen oder einen Gemeinde- oder Polizeibeamten als Zeugen zuzuziehen. '''(Quellinfo = Buch "ZPO" S. 177 ff.)'''
= § 760 (ZPO) Akteneinsicht: Aktenabschrift =
1 Jeder Person, die bei dem Vollstreckungsverfahren beteiligt ist, muss auf Begehren Einsicht der Akten des Gerichtsvollziehers gestattet und Abschrift einzelner Aktenstücke erteilt werden. 2 Werden die Akten des Gerichtsvollziehers elektronisch geführt, erfolgt die Gewährung von Akteneinsicht durch Erteilung von Ausdrucken, durch Übermittlung von elektronischen Dokumenten oder durch Wiedergabe auf einem Bildschirm; dies gilt auch für die nach §§ 885 a Absatz 2 Satz 2 elektronisch gespeicherten Dateien, '''(Quellinfo = Buch "ZPO" S. 178 ff.)'''
= § 761 (ZPO) - (weggefallen) =
'''(Quellinfo = Buch "ZPO" S. 178 ff.)'''
= § 762 (ZPO) Protokoll über Vollstreckungshandlungen =
(1) DerGerichtsvollzieher hat über jede Vollstreckungshandlung ein Protokoll aufzunehmen. (2) Das Protokoll muss enthalten: 1. Ort und Zeit der Aufnahmen: 2. den Gegenstand der Vollstreckungshandlung unter kurzer Erwähnung der wesentlichen Vorgänge. 3. die Namen der Personen, mit denen verhandelt ist; 4. die Unterschrift dieser Personen und den Vermerk, dass die Unterzeichnung nach Vorlesung oder Vorlegung zur Durchsicht und nach Genehmigung erfolgt sei: 5. die Unterschrift des Gerichtsvollziehers. (3) Hat einem der unter Nummer 4 bezeichneten Erfordernisse nicht genügt werden können, so ist der Grund anzugeben. '''(Quellinfo = Buch "ZPO" S. 178 ff.)'''
= § 763 (ZPO) Aufforderungen und Mitteilungen =
(1) 1 Die Aufforderungen und sonstigen Mitteilungen, die zu den Vollstreckungshandlungen gehören, sind von dem Gerichtsvollzieher mündlich zu erlassen und vollständig in das Protokoll aufzunehmen. (2) 1 Kann dies mündlich nicht ausgeführt werden, so hat der Gerichtsvollzieher eine Abschrift des Protokolls zuzustellen oder durch die Post zu übersenden. 2 Es muss im Protokoll vermerkt werden, dass diese Vorschrift befolgt ist. 3 Eine öffentliche Zustellung findet nicht statt. '''(Quellinfo = Buch "ZPO" S. 178 ff.)'''
= § 764 (ZPO) Vollstreckungsgericht =
(1) Die den Gerichten zugewiesene Anordnung von Vollstreckungshandlungen und Mitwirkung bei solchen gehört zur Zuständigkeit der Amtsgerichte als Vollstreckungsgerichte. (2) Als Vollstreckungsgericht ist, sofern nicht das Gesetz ein anderes Amtsgericht bezeichnet, das Amtsgericht anzusehen, in dessen Bezirk das Vollstreckungsverfahren stattfinden soll oder stattgefunden hat. (3) Die Entscheidungen des Vollstreckungsgerichts ergehen durch Beschluss. '''(Quellinfo = Buch "ZPO" S. 178 ff.)'''
= § 765 (ZPO) Vollstreckungsgerichtliche Anordnungen bei Leistung Zug um Zug. =
1 Hängt die Vollstreckung von einer Zug um Zug zu bewirkenden Leistung des Gläubigers an den Schuldner ab, so darf das Vollstreckungsgericht eine Vollstreckungsmaßregel nur anordnen, wenn 1. der Beweis, dass der Schuldner befriedigt oder im Verzug der Annahme ist, durch öffentliche oder öffentlich beglaubigte Urkunden geführt wird und ein Abschrift dieser Urkunden bereits zugestellt ist; der Zustellung bedarf es nicht, wenn bereits der Gerichtsvollzieher die Zwangsvollstreckung nach § 756 Abs. 1 begonnen hatte und der Beweis durch das Protokoll des Gerichtsvollziehers geführt wird; oder
2. der Gerichtsvollzieher eine Vollstreckungsmaßnahme nach § 756 Abs. 2 durchgeführt hat und diese durch das Protokoll des Gerichtsvollziehers nachgewiesen ist. '''(Quellinfo = Buch "ZPO" S. 178 ff.)'''
= § 765 a (ZPO) Vollstreckungsschutz. =
(1) 1 Auf Antrag des Schuldners kann das Vollstreckungsgericht eine Maßnahme der Zwangsvollstreckung ganz oder teilweise aufheben, untersagen oder einstweilen einstellen, wenn die Maßnahme unter voller Würdigung des Schutzbedürfnisses des Gläubigers eggen ganz besonderer Umstände eine Härte bedeutet, die mit den guten Sitten nicht vereinbar ist. 2 Es ist befugt, die in § 732 Ab. 2 bezeichneten Anordnungen zu erlassen. 3 Betrifft die Maßnahme ein Tier, so hat das Vollstreckungsgericht bei der von ihm vorzunehmenden Abwägung die Verantwortung ges Menschen für das Tier zu berücksichtigen. (2) Eine Maßnahme zur Erwirkung der Herausgabe von Sachen kann der Gerichtsvollzieher bis zur Entscheidung des Vollstreckungsgerichts, jedoch nicht länger als eine Woche aufschieben, wenn ihm die Voraussetzungen des Absatzes 1 Satz 1 glaubhaft gemacht werden und dem Schulter die rechtzeitige Anrufung Tees Vollstreckungsgerichts nicht möglich war. (3) In Räumungssachen ist der Antrag nach Absatz 1 spätestens zwei Wochen vor dem festgesetzten Räumungstermin zu stellen, es sei denn dass die Gründe , auf denen der Antrag beruht, erst nach diesem Zeitpunkt entstanden sind oder der Schuldner ohne sein Verschulden an einer rechtzeitigen Antragstellung gehindert war. (4) Das Vollstreckungsgericht hebt seinen Beschluss auf Antrag auf oder ändert ihn, wenn dies mit Rücksicht auf eine Änderung der Sachlage geboten ist. (5) Die Aufhebung von Vollsrteckungsmaßregeln erfolgt in den Fällen des Absatzes 1 Satz 1 und des Absatzes 4 erst nach Rechtskraft des Beschlusses. '''(Quellinfo = Buch "ZPO" S. 179 ff.)'''
= § 766 (ZPO) Erinnerung gegen Art und Weise der Zwangsvollstreckung. =
(1) 1 Über Anträge, Einwendungen und Erinnerungen, welche die Art und Weise der Zwangsvollstreckung oder das vom Gerichtsvollzieher bei ihr zu beobachtende Verfahren betreffen, entscheidet das Vollstreckungsgericht. 2 Es ist befugt, die im § 732 Abs. 2 bezeichenden Anordnungen zu erlassen. (2) Dem Vollstreckungsgericht steht auch die Entscheidung zu, wenn ein Gerichtsvollzieher sich weigert, einen Vollstreckungsauftrag zu übernehmen oder eine Vollstreckungshandlung dem Auftrag gemäß auszuführen, oder wenn wegen der von dem Gerichtsvollzieher in Ansatz gebrachten Kosten Erinnerungen erhoben werden. '''(Quellinfo = Buch "ZPO" S. 179 ff.)'''
= § 767 (ZPO) Vollstreckungsabwehrklage. =
(1) Einwendungen, die den durch das Urteil festgestellten Anspruch selbst betreffen, sind von dem Schuldner im Wege der Klage bei dem Prozessgericht des ersten Rechtszuges geltend zu machen. (2) sie sind nur insoweit zulässig, als die Gründe auf denen sie beruhen, erst nach dem Schluss der mündlichen Verhandlung, in der Einwendungen nach den Vorschriften dieses Gesetzes spätestens hätten geltend gemacht werden müssen, entstanden sind und durch Einspruch nicht mehr geltend gemacht werden können. (3) Der Schuidner muss in der von ihm zu erhebenden Klage alle Einwendungen geltend machen, die er zur Zeit der Erhebung der Klage geltend zu machen imstande war. '''(Quellinfo = Buch "ZPO" S. 180 ff.)'''
= § 768 (ZPO) Klage gegen Vollstreckungsklausel. =
Die Vorschriften des § 767 Abs. 1, 3 gelten entsprechend, wenn in den Fällen des § 726 Abs. 1, der §§ 727 bis 729, 738. 742, 744, des § 749 der Schuldner den bei der Erteilung der Vollstreckungsklausel als beweisen angenommenen Eintritt der Voraussetzung für die Erteilung der Vollstreckungsklausel bestreitet, unbeschadet der Befugnis des Schuldners, in diesen Fällen Einwendungen gegen die Zulässigkeit der Vollstreckungsklausel nach § 732 zu erheben. '''(Quellinfo = Buch "ZPO" S. 180 ff.)'''
= § 769 (ZPO) Einstweilige Anordnungen. =
(1) 1 Das Prozessgericht kann auf Antrag anordnen, dass bis zum Erlass des Urteils über die in den §§ 767, 768 bezeichneten Einwendungen die Zwangsvollstreckung gegen oder ohne Sicherheitsleistung eingestellt per nur gegen Sicherheitsleistung fortgesetzt werde und das Vollstreckungsmaßregeln gegen Sicherheitsleistung aufzuheben seien. 2 Es setzt eine Sicherheitsleistung für die Einstellung der Zwangsvollstreckung nicht fest, wenn der Schuldner zur Sicherheitsleistung nicht in der Lage ist und die Rechtsverfolgung durch ihn hinreichende Aussicht auf Erfolg bietet. 3 Die tatsächlichen Behauptungen, die den Antrag begründen, Erfolg bietet. 3 Die tatsächlichen Behauptungen, die den Antrag begründen sind glaubhaft zu machen. (2) 1 In dringenden Fällen kann das Vollstreckungsgericht eine solche Anordnung erlassen, unter Bestimmung einer Frist innerhalb der die Entscheidung des Prozessgerichts beizubringen sei. 2 Nach fruchtlosem Ablauf der Frist wird die Zwangsvollstreckung fortgesetzt. (3) Die Entscheidung über diese Anträge ergeht durch Beschluss. (4) Im Fall der Anhängigkeit einer auf Herabsetzung gerichteten Abänderungsklage gelten die Absätze 1 bis 3 entsprechend. '''(Quellinfo = Buch "ZPO" S. 180 ff.)'''
= § 770 (ZPO) Einstweilige Anordnungen im Urteil. =
<sup>1</sup>Das Prozessgericht kann in dem Urteil, durch das über die Einwendungen entschieden wird, die in dem vorstehendem Paragraphen bezeichneten Anordnungen erlassen oder die bereits erlassenen Anordnungen aufheben, abändern oder bestätigen. <sup>2</sup> Für die Anfechtungen einer solchen Entscheidung gelten die Vorschriften des § 718 entsprechend. '''(Quellinfo = Buch "ZPO" S. 184 ff.)'''
= § 771 (ZPO) Drittwiderspruchsklage. =
(1) Behauptet ein Dritter, dass ihm an dem Ggenstnd der Zwangsvollstreckung ein die Veräußerung hinderndes Recht zustehe, so ist der Widerspruch gegen die Zwangsvollstreckung im Wege der Klage bei dem Gericht geltend zu machen, in dessen Bezirk die Zwangsvollstreckung erfolgt. (2) Wird die Klage gegen den gläubiger und den Schuldner gerichtet, so sind diese als Streitgenossen anzusehen. (3)<sup>1</sup> Auf die Einstellung der Zwangsvollstreckung und die Aufhebung der bereits getroffenen Vollstreckungmapregeln sin die Vorschriften der §§ 769, 770 entsprechend anzuwenden. <sup>2</sup> Die Aufhebung einer Vollstreckungsmaßregel ist auch ohne Sicherheitsleistung zulässig. '''(Quellinfo = Buch "ZPO" S. 184 ff.)'''
= § 772 (ZPO) Drittwiderspruchsklage bei Veräußerungsverbot. =
<sup>1</sup>Solange ein Veräußerungsverbot der in den §§ 135,136 des Bürgerlichen Gesetzbuchs bezeichneten Art besteht, soll der Gegenstand auf den es sich bezieht, wegen eines persönlichen Anspruchs oder auf Grund eines infolge des Verbots unwirksamen Rechts nicht im Wege der Zwangsvollstreckung veräußert oder überwiesen werden. <sup>2</sup>Auf Grund des Veräußerungsverbots kann nach Maßgabe des § 771 Widerspruch erhoben werden.
= § 773 (ZPO) Drittwiderspruchsklage des Nacherben. =
= § 774 (ZPO) Drittwiderspruchsklage des Ehegatten oder Lebenspartners. =
= § 775 (ZPO) Einstellung oder Beschränkung der Zwangsvollstreckung. =
= § 776 (ZPO) Aufhebung von Vollstreckungsmaßregeln. =
= § 777 (ZPO) Erinnerung bei genügender Sicherung des Gläubigers. =
= § 778 (ZPO) Zwangsvollstreckung vor Erbschaftsnahme. =
= § 779 (ZPO) Fortsetzung der Zwangsvollstreckung nach dem Tod des Schuldners. =
= § 780 (ZPO) Vorbehalt der beschränkten Erbenhaftung. =
::'''Titel 2. Zwangsvollstreckung in das bewegliche Vermögen'''
: '''Untertitel 1. Allgemeine Vorschriften'''
= § 802 <sup>1</sup>(ZPO) Auskunftsrechte des Gerichtsvollziehers. =
= § 803 (ZPO) Pfändung. =
(1) 1 Die Zwangsvollstreckung in das bewegliche Vermögen erfolgt durch Pfändung. 2 Sie darf nicht weiter ausgedehnt werden,als es zur Befriedigung des Gläubigers und zur Deckung der Kosten der Zwangsvollstreckung erforderlich ist. (2) Die Pfändung hat zu unterbleiben, wenn sich von der Verwertung der zu pfändenden Gegenstände ein Überschuss über die Kosten der Zwangsvollstreckung nicht erwarten lässt. '''(Quellinfo = Buch "ZPO" S. 200 ff.)'''
= § 804 (ZPO) Pfändungsrecht. =
(1) Durch die Pfändung erwirbt der Gläubiger ein Pfandrecht an dem gepfändeten Gegenstande. (2) Das Pfandrecht gewährt dem Gläubiger im Verhältnis zu anderen Gläubigern dieselben Rechte wie ein durch Vertrag erworbenes Faustpfandrecht; es geht Pfand- und Vorzugsrechten vor, die für den Fall eines Insolvenzverfahrens den Faustpfandrechten nicht gleichgestellt sind. 1) (3) Das durch eine frühere Pfändung begründete Pfandrecht geht demjenigen vor, das durch eine spätere Pfändung begründet wird. '''(Quellinfo = Buch "ZPO" S. 200 ff.)'''
= § 829 a (ZPO) Vereinfachter Vollstreckungsantrag bei Vollstreckungsbescheiden. =
Text folgt noch!
= § 830 (ZPO) Pfändung einer Hypothekenforderung. =
Text folgt noch!
= § 830 a (ZPO) Pfändung einer Schiffshypothekenforderung. =
Text folgt noch!
= § 831 a (ZPO) Pfändung indossabler Papiere. =
Text folgt noch!
= § 832 (ZPO) Pfändungsumfang bei fortlaufenden Bezügen. =
Text folgt noch!
= § 833 (ZPO) Pfändungsumfang bei Arbeits- und Diensteinkommen . =
Text folgt noch!
= § 833 a (ZPO) Pfändungsumfang bei Kontoguthaben. =
Text folgt noch!
= § 834 (ZPO) Keine Anhörung des Schuldners. =
Text folgt noch!
= § 835 a (ZPO) Überweisung einer Geldforderung. =
Text folgt noch!
= § 836 <sup>1</sup> (ZPO) Wirkung der Überweisung. =
Text folgt noch!
= § 837 (ZPO) Überweisung einer Hypothekenforderung. =
Text folgt noch!
= § 837 a (ZPO) Überweisung einer Schiffshypothekenforderung. =
Text folgt noch!
= § 838 (ZPO) Einrede des Schuldners bei Faustpfand. =
Text folgt noch!
= § 839 (ZPO) Überweisung bei Abwendungsbefugnis. =
Text folgt noch!
= § 840 (ZPO) Erklärungspflicht des Drittschuldners. =
Text folgt noch!
= § 841 (ZPO) Pflicht zur Streitverkündung. =
Text folgt noch!
= § 842 (ZPO) Schadenersatz bei verzögerter Beitreibung. =
Text folgt noch!
= § 843 (ZPO) Verzicht des Pfandgläubigers. =
Text folgt noch!
= § 844 (ZPO) Andere Verwertungsart. =
Text folgt noch!
= § 845 <sup>1</sup> (ZPO) Vorpfändung. =
Text folgt noch!
= § 846 (ZPO) Zwangsvollstreckung in Herausgabeansprüche. =
Text folgt noch!
= § 847 (ZPO) Herausgabeanspruch auf eine bewegliche Sache. =
Text folgt noch!
= § 847 a (ZPO) Herausgabeanspruch auf ein Schiff. =
Text folgt noch!
= § 848 (ZPO) Herausgabeanspruch auf eine unbewegliche Sache. =
Text folgt noch!
= § 849 (ZPO) Keine Überweisung an Zahlungs statt. =
Text folgt noch!
= § 850 (ZPO) Pfändungsschutz für Arbeitseinkommen. =
(1) Arbeitseinkommen, das in Geld zahlbar ist, kann nur nach Maßgabe der §§ 850a bis 850i gepfändet werden. (2) Arbeitseinkommen im Sinne dieser Vorschrift sin die Dienst- und Versorgungsbezüge der Beamten, Arbeits- und Dienstlöhne. Ruhegelder und ähnliche nach dem einstweiligen oder dauernden Ausscheiden aus dem Dienst- oder Arbeitsverhältnis gewährte fortlaufende Einkünfte, ferner Hinterblebenenbezüge, soweit sonstige Vergütungen für Dienstleistungen aller Art, die die Erwerbstätigkeit des Schuldners vollständig oder zu einem wesentlichen Teil in Anspruch nehmen. (3) Abeitseinkommen und auchdiefeolgenden Bezüge, soweit sie in Geld zahlbar sind:
:: a) Bezüge, die ein Arbeitnehmer zum Ausgleich für Wettbewerbsbeschränkungen fpr die Zeit nach Beendigung eines inestverhältnisses beanspruchen kann:
:: b) Renten, die auf Grund von Versicherungsunternehmen oder seiner unterhaltsberechtigten Angehörigen eingegangen sind.
(4) Die Pfändung des in Geld zahlbaren Arbeitskommens erfasst alle Vergütungen, die dem Schuldner aus der Arbeits- oder Dienstleistung zustehen, ohne Rücksicht auf ihre Benennung oder Berechnungsart. '''(Quellinfo = Buch "ZPO" S. 216 ff.)'''
= § 850 a (ZPO) Unpfändbare Bezüge. =
Unpfändbar sind
1. zur Hälfte die für die Leistung von Mehrarbeitsstunden gezahlten Teile des Arbeitsseinkommens; 2. die für die Dauer eines Urlaubs über das Arbeitseinkommen hinaus gewährten Bezüge, Zuwendungen aus Anlass eines besonderen Betriebsereignisses und Treugelder, soweit sie den Rahmen des Üblichen nicht übersteigen; 3. Aufwandsentschädigungen, Auslösungsgelder und sonstige soziale Zulagen für auswärtige Beschäftigungen, das Entgelt für selbstgestelltes Arbeitsmaterial. Gefahrenzulagen, sowie Schmutz und Erschwerniszulagen, soweit diese Bezüge den Rahmen des Üblichen nicht übersteigen; 4. Weihnachtsvergütungen bis zum Betrag der Hälfte des monatlichen Arbeitseinkommens, höchstens aber bis zum Betrag von 500 Euro; 5. Geburtsbeihilfen sowie Beihilfen aus Anlass der Eingehung einer Ehe oder Begründung einer Lebenspartnerschaft, sofern die Vollstreckung wegen anderer als der aus Anlass der Geburt, der Eingebung einer Ehe oder der Begründung einer Lebenspartnerschaft entstandenen Ansprüche betrieben wird; 6. Erziehungsgelder, Studienbeihilfen und ähnliche Bezüge; 7. Sterbe- und Gnadenbezüge aus Arbeits- und Dienstverhältnissen; 8. Blindenzulagen. '''(Quellinfo = Buch "ZPO" S. 217 ff.)'''
= § 850 b (ZPO) Bedingt pfändbare Bezüge. =
Text folgt noch!
= § 850 c<sup>1</sup> (ZPO) Pfändungsgrenzen für Arbeitseinkommen. =
Text folgt noch!
= § 850 d (ZPO) Pfändbarkeit bei Unterhaltsansprüchen. =
Text folgt noch!
= § 850 e<sup>1</sup> (ZPO) Berechnung des pfändbaren Arbeitseinkommens. =
Text folgt noch!
= § 850f (ZPO) Änderung des unpfändbaren Betrages. =
Text folgt noch!
= § 850g (ZPO) Änderung der Unpfändbarkeitsvoraussetzungen. =
Text folgt noch!
= § 886 (ZPO) Herausgabe bei Gewahrsam eines Dritten. =
Befindet sich eine herauszugebende Sache im Gewahrsam eines Dritten, so ist dem Gläubiger auf dessen Antrag der Anspruch des Schuldners auf Herausgabe der Sache nach den Vorschriften zu überweisen, welche die Pfändung und Überweisung einer Geldforderung betreffen. '''(Quellinfo = Buch "ZPO" S. 242 ff.)'''
:::::::'''Abschnitt 6. Schiedsspruch und Beendigung des Verfahrens'''
= § 1051 (ZPO) Anwendbares Recht.=
(1) <sup>1</sup> Das Schiedsgericht hat die Streitigkeit in Übereinstimmung mit den Rechtsvorschriften zu entscheiden, die von den Parteien als auf den Inhalt des Rechtsstreits anwendbar bezeichnet worden sind. <sup>2</sup> Die Bezeichnung des Rechts oder der Rechtsordnung eines bestimmten Staats ist, sofern die Parteien nicht ausdrücklich etwas anderes vereinbart haben, als unmittelbare Verweisung auf die Sachvorschriften dieses Staates und nicht auf sein Kollisionsrecht zu verstehen. (2) Haben die Parteien die anwendbaren Rechtsvorschriften nicht bestimmt, so hat das Schiedsgericht das Recht des Staates anzuwenden, mit dem der Gegenstand des Verfahrens die engsten Verbindungen aufweist. (3) <sup>1</sup> Das Schiedsgericht hat dann nach Billigkeit zu entscheiden, wenn die Parteien es ausdrücklich dazu ermächtigt haben. <sup>2</sup> Die Ermächtigung kann bis zur Entscheidung des Schiedsgerichts erteilt werden. (4) In allen Fällen hat das Schiedsgericht in Übereinstimmung mit den Bestimmungen des Vertrages zu entscheiden und dabei bestehende Landesbräuche zu berücksichtigen.
= § 1052 (ZPO) Entscheidung durch ein Schiedsrichterkollegium.=
= § 1053 (ZPO) Vergleich.=
= § 1054 (ZPO) Form und Inhalt des Schiedsspruchs.=
= § 1055 (ZPO) Wirkungen des Schiedsspruchs.=
= § 1056 (ZPO) Beendigung des schiedsrichterlichen Verfahrens.=
tfre04aenum9639pzs89gbgim44w56e
Traktorenlexikon: Schiltrac
0
108260
1090626
1059516
2026-09-09T16:42:25Z
~2026-46367-92
116784
1090626
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation}}
Die schweizer Firma Schiltrac führt den Fahrzeugbau der [[Traktorenlexikon: Schilter|Schilter Fahrzeuge]] weiter.
==Geschichte==
* 1992 übernimmt die Firma '''Schiltrac Fahrzeugbau GmbH''' den Hersteller [[Traktorenlexikon: Schilter|Schilter Fahrzeugbau AG]]
== Typen ==
* {{:Traktorenlexikon: Create|2001}} 20 PS, 1991-199? <ref>[https://typenscheine.ch/de/Info/8S1501-SCHILTRAC2001 Typenschein 8S1501 Schiltrac 2001] in: typenscheine.ch</ref><ref>[https://www.agropool.ch/static/ams-prod/DBmWtLdZY0aw7Y9CbMz0sA Prospekt Schiltrac 2001] in: agropool.ch</ref>
<br>
* {{:Traktorenlexikon: Create|9036 Z}} 36 PS, 1993-1998 <ref>[https://typenscheine.ch/de/Info/8S1505-SCHILTRAC9036Z Typenschein 8S1505 Schiltrac 9036 Z] in: typenscheine.ch</ref>
* {{:Traktorenlexikon: Create|9048}} 48 PS, 1993-1998 <ref>[https://typenscheine.ch/de/Info/8S1504-SCHILTRAC9048 Typenschein 8S1504 Schiltrac 9048] in: typenscheine.ch</ref>
* {{:Traktorenlexikon: Create|9050}} 50 PS, 1993-1998
* {{:Traktorenlexikon: Create|9060}} 59 PS, 1993-1998 <ref>[https://typenscheine.ch/de/Info/8S1502-SCHILTRAC9060 Typenschein 8S1502 Schiltrac 9060] in: typenscheine.ch</ref>
* {{:Traktorenlexikon: Create|9065}} 56 PS, 1995-1998 <ref>[https://typenscheine.ch/de/Info/8S1507-SCHILTRAC9065 Typenschein 8S1507 Schiltrac 9065] in: typenscheine.ch</ref>
* {{:Traktorenlexikon: Create|9075}} 75 PS, 1995-1998
<br>
* {{:Traktorenlexikon: Create|2068}} -2000-
* {{:Traktorenlexikon: Create|2068 SF}} -2004-
<br>
* {{:Traktorenlexikon: Create|92}} 92E 92S 92F 92 PS
<br>
* {{:Traktorenlexikon: Create|EUROTRANS 4100}}
* {{:Traktorenlexikon: Create|EUROTRANS 6150}}
* {{:Traktorenlexikon: Create|EUROTRANS CVT 6150}}
* {{:Traktorenlexikon: Create|EUROTRANS AGRO}}
* {{:Traktorenlexikon: Create|SWISSTRANS RST 2950}}
== Weblinks ==
* [https://schiltrac.ch/verkauf-nostalgie/nostalgie.html Schiltrac Nostalgie]
* [https://www.youtube.com/watch?v=KjDoM0PDyBE SCHILTRAC - Die Landtechnik-Legende aus der SCHWEIZ] 2026, 05:05 Min. (YouTube)
== Einzelnachweise ==
<references/>
{{:Traktorenlexikon: Navigation}}
snepjsnvoyzrxy5s4ucyag937ryg9em
Wikibooks:GUS2Wiki
4
116489
1090641
1090278
2026-09-10T04:50:54Z
Alexis Jazz
96587
Updating gadget usage statistics from [[Special:GadgetUsage]] ([[phab:T121049]])
1090641
wikitext
text/x-wiki
{{#ifexist:Project:GUS2Wiki/top|{{/top}}|This page provides a historical record of [[Special:GadgetUsage]] through its page history. To get the data in CSV format, see wikitext. To customize this message or add categories, create [[/top]].}}
Diese Daten stammen aus dem Cache. Der Zeitpunkt der letzten Aktualisierung: 2026-09-07, 05:53:02Z Uhr. Maximal {{PLURAL:5000|ein Ergebnis ist|5000 Ergebnisse sind}} im Cache verfügbar.
{| class="sortable wikitable"
! Helferlein !! data-sort-type="number" | Anzahl der Benutzer !! data-sort-type="number" | Aktive Benutzer
|-
|CollapseAll || 31 || 4
|-
|HotCat || 27 || 2
|-
|Pfeil-hoch || 79 || 3
|-
|displayRealTitle || 18 || 2
|-
|editSectionLink || 115 || 2
|-
|erstelleSammlung || 89 || 1
|-
|extra-editbuttons || 199 || 1
|-
|mfnf-linter || data-sort-value="Infinity" | Standard || data-sort-value="Infinity" | Standard
|-
|navigation-popups || 25 || 1
|-
|serlo-design || data-sort-value="Infinity" | Standard || data-sort-value="Infinity" | Standard
|-
|setupTitle || 53 || 0
|-
|showAnchors || 42 || 5
|-
|wikEd || 175 || 3
|}
* [[Spezial:GadgetUsage]]
* [[m:Meta:GUS2Wiki/Script|GUS2Wiki]]
<!-- data in CSV format:
CollapseAll,31,4
HotCat,27,2
Pfeil-hoch,79,3
displayRealTitle,18,2
editSectionLink,115,2
erstelleSammlung,89,1
extra-editbuttons,199,1
mfnf-linter,default,default
navigation-popups,25,1
serlo-design,default,default
setupTitle,53,0
showAnchors,42,5
wikEd,175,3
-->
84clcwnto1gq49tegx2ugkp55dfnx0g
Benutzer:PantheraLeo1359531/Geschichte der Computertechnik
2
116582
1090637
1089379
2026-09-09T20:17:52Z
PantheraLeo1359531
93738
/* 2026 */
1090637
wikitext
text/x-wiki
Diese Seite ist im dauerhaften Aufbau und soll niemals abgeschlossen sein. Das Thema umfasst viele bedeutsame Entwicklungen und Technologien, die heute im Umgang mit Computertechnologie Standard sind, aber auch Produkte, die sich millionenfach verkauft haben. Deshalb kann es dauern, bis viele wichtige Punkte aufgelistet sind.
Diese Seite möchte Errungenschaften in der Computertechnik (und davor) nach Jahren gruppiert auflisten. Hierbei soll jedoch neben der reinen Technik auch zusammenhängende Bereiche wie Ereignisse in der Computerspielbranche oder der Softwareentwicklung eingebracht werden. Der Computer als digitale Rechenmaschine arbeitet hinlänglich mit Strom. Auch miteingefügt sollen jedoch Jahre, die der Computertechnik vorausgehen (Bspw. Ära Zuse und Turing), aber auch die antike Geschichte der Rechnung. Aussagen werden wenn möglich mit Belegen ergänzt.
Diese Seite deckt mehrere Themen rund um die Computertechnik ab.
{{info}} In diesem Text sind einige Tipp-, Rechtschreib- und Grammatikfehler. Es ist geplant, diese zu korrigieren.
Zum Vergleich sollten CPUs, GraKas usw. mehrerer Hersteller einbezogen werden.
Rot gefärbte Texte beschreiben Zeiträume, die noch nicht geschehen sind. Hier aufgelistete Punkte sind unsicher und können sich noch ändern.
In jedem Jahr ist folgender Aufbau geplant:
<code><nowiki>==Jahr==</nowiki></code>
# Fließtext für tiefergehende Erläuterungen zu Errungenschaften und Ereignissen
# Chronologische, sitchpunktartige Auflistung von kürzer beschriebenenen Ereignissen
# Tabelle mit Spezifikationen einer Komponente oder Mindestanforderungen der Hardware. Dies dient dem Vergleich der Entwicklung über die Zeit. Es werden in den einzelnen Jahren neue Releases von Hardware wie CPUs und GPUs vorgestellt. Diese zeigen die Entwicklung und den Fortschritt in der Leistung, und ob etwa das Mooressche Gesetz greift.
# Bildergalerie mit korrespondierenden Grafiken, Logos, Fotos der Vorrichtungen, etc.
Fehlt:
* Errungenschaften Alan Turings
* Technologien wie Anschlüsse oder Technik-Standards (Audio, Normungen, usw.)
==18. Jahrtausend vor der Zeitenwende==
* Der {{w|Ishango-Knochen}} wird angewandt. Er gilt als einer der ersten Systeme, die der Zählung dienen.
<gallery>
Os d'Ishango IRSNB.JPG|Ein Ishango-Knochen
</gallery>
==03. Jahrtausend vor der Zeitenwende==
* um 3300: Die sumerische Sprache wird als eine der ersten Sprachen mit einem Schriftsystem. Hiermit war es nun möglich, eine Alternative zur mündlichen Überlieferung von Informatioin zu nutzen.
* Der erste Abakus wird gebaut. Vereinfacht gesagt kann man sagen, dass es ein alter Vorfahr des Rechenschiebers ist.
<gallery>
Sumerian 26th c Adab.jpg|Sumerische Sprache niedergeschrieben
RomanAbacusRecon.jpg|Ein Abakus aus der Antike. Die Kugeln werden hin- und hergeschoben, was einem Zählen gleichkommt
</gallery>
==01. Jahrhundert==
* Der Mechanismus von Antikythera wird gebaut. Es ist eine Art Rechenmaschine, die als astronomische Uhr fungiert. Das System ist nicht mehr ganz erhalten.
<gallery>
NAMA Machine d'Anticythère 1.jpg|Ein seeeehr altes Rechensystem
</gallery>
==15. Jahrhundert==
* Mitte des 15. Jhdts.: Mit dem durch Gutenberg erfundenen Buchdruck wird eine frühe Version des Kopierens ermöglicht. Informationen sind nun schneller verbreitbar.
<gallery>
Buchdrucker-1568.png|Der Buchdruck
</gallery>
==16. Jahrhundert==
* Das Prinzip dess Passworts ist belegt aus in dieser Zeit existent. In der digitalen Zeit dient er als Authentifikation, um Zugriff auf bestimmte Dienste oder Daten zu erhalten.
==17. Jahrhundert==
* 1642: {{w|Blaise Pascal}} erfindet die {{w|Pascaline}}. Diese mechanische Rechenmaschine ist eine der ersten mechanischen Rechenmaschinen.
* Das Dualsystem (binäres Zahlensystem) von Gottfried Wilhelm Leibniz legt die Grundlage für das Dualsystem für Binärrechner.
<gallery>
Arts et Metiers Pascaline dsc03869.jpg|Eine Pascaline aus 1652
Leibniz binary system 1697.jpg|Das Leibnizsche Dualsystem
</gallery>
==19. Jahrhundert==
===1837===
* Der Mathematikprofessor {{w|Charles Babbage}} veröffentlicht den Entwurf der {{w|Analytical Engine}}. Die Maschine ist eine mechanische Rechenmaschine.
<gallery>
Babbages Analytical Engine, 1834-1871. (9660574685).jpg|Ein Modell der Analytical Engine
Charles Babbage 1860.jpg|Babbage in 1871
</gallery>
===1847===
* George Boole erfindet die Boolesche Algebra. Sie ist elementar für den Booleschen Datentyp und logische Gatter und ist in Computern zu finden.
<gallery>
B functies 2var versie04 eng.png|Boolesche Operatoren in einer zusammenhängenden Grafik
George Boole color.jpg|Boole um 1860
</gallery>
===1870===
* 1870er: Der Burckhardt {{w|Arithmometer}} geht als erste deutsche Rechenmaschine in Serienproduktion. Es ist eine mobile mechanische Rechenmaschine. Arithmometer ist zusammengesetzt aus altgriechisch "arithmos" (Zahl) und "metron" (Maß, Messgerät). Der Arithmometer selbst geht auf {{w|Charles Xavier Thomas de Colmar}} zurück.
<gallery>
Arithmometre.jpg|Ein Arithmometer aus 1887
Arithmometer Colmar 1852.jpg|Colmar Arithmometer, 1852
Tomas De Colmer Arithmometer, 1821 - Ridai Museum of Modern Science, Tokyo - DSC07591.JPG|Colmar Arithmometer, 1821
</gallery>
===1887===
* {{w|Herman Hollerith}} stellt die elektromechanischen Auswertungsmaschine vor. Die Tabelliermaschine arbeitet mit Lochkarten, die bis weit in die Mitte des 20. Jahrhunderts hinein genutzt werden. Die Hollerith-Lochkarten stammen von ihm.
* Mit dem {{w|Comptometer}} gibt es eine mechanische Rechenmaschine, dessen Bedienung rein durch Tasten geschieht.
<gallery>
HollerithMachine.CHM.jpg|Eine Maschine nach Hollerith
Victor-comptometer.JPG|Ein zehnstelliger Victor-Comptometer
Duodecillion Comptometer.jpg|Duodecillion Comptometer von 1915 (Duodezillion ist auch eine Zahl: 10<sup>72</sup>)
EarlyComptometerKeyboard.png|Tastatur eines Comptometers
</gallery>
==20. Jahrhundert==
===1918===
* 21.06.1918: Die {{w|Flipflop}}-Schaltung wird patentiert. Damit kann eine Kippstufe ein Bit beliebig lange speichern.
<gallery>
Basic Measuring Instruments - Math Processor 83002190 - Motorola MC74ACT74N-3930.jpg|Die Flipflop-Schaltung in der Praxis
Flipflop SR2.svg|Ein Flipflop aus NAND-Gattern
</gallery>
===1932===
* Die Mehrfachsteckdose wird patentiert. Sie bildet die Grundlage für viele Computersysteme daheim.
<gallery>
Power strips with extension cord.jpg|Mehrfachsteckdosen bilden das Rückgrat moderner Infrastruktur
</gallery>
===1933===
* Der sogenannte Telex (TELeprinter EXchange) wird im Deutschen Reich zur Anwendung gebracht. Das Fernschreiben ist ein Vorgänger des Telefax und der Email. Beim Telex werden über das Telefonnetz Textnachrichten versendet.
<gallery>
Siemens T100 Telex.jpg|Siemens T100 mit Telex-Unterstützung
SiemensTelex.jpg|Ein weiteres Telex-Gerät
</gallery>
===1936===
* Mit dem [[w:en:World Brain]] soll eine weltumspannende Enzyklopädie als Urahn der Wikipedia etabliert werden. Durch den Zugriff auf universelle Informationsquellen will man einen Beitrag zum Weltfrieden machen.
===1937===
* Konrad Zuse baut die Zuse Z1
* 11.1937: George Stibitz vollendet einen Rechner mit Relaistechnik, welcher additiv mit dem Dualsystem umgehen kann
<gallery>
Konrad Zuse (1992).jpg|Konrad Zuse in 1992
Zuse Z1-2.jpg|Ein Nachbau des Zuse Z1
</gallery>
===1939===
* Die Zuse Z2 wird fertiggestellt. Er dient der Testung des Relais. Der Rechner taktet in etwa 10 Hertz und kann mit den vier Grundrechenarten umgehen.
===1940===
* Der zelluläre Automat wird vorgestellt. Er arbeitet mit Zellen und einer gewissen Systematik, die über Codes und Skripte programmiert werden können.
===1941===
* Mit der Zuse Z3 wird einer der ersten modernen Computer gebaut
* Der Atanasoff-Berry-Computer wird fertiggestellt. Es ist eines der ersten elektronischen Digitalrechner.
<gallery>
Z3 Deutsches Museum.JPG|Der Nachbau des Zuse Z3
Atanasoff-Berry Computer at Durhum Center.jpg|Der ABC
</gallery>
===1942===
* Das Plankalkül wird begonnen zu entwickeln. Es ist die erste höhere Programmiersprache der Welt.
* {{w|Isaac Asimov}} beschreibt die {{w|Robotergesetze}} als ''Grundregeln des Roboterdienstes''. Der Begriff ''Roboter'' soll 1920 erstmals erwähnt worden sein.
<gallery>
Isaac.Asimov01.jpg|Asimov in 1965
</gallery>
===1945===
* Die Zuse Z4 wird fertiggestellt. Sie ist ein Digitalrechner, der 2200 Relais nutzt. 64 Zahlen kann der elektromechanische Speicher aufnehmen. Die Z4 ist der erste kommerziell vertriebene Computer. Elementar für die Z4 waren Lochstreifen.
* Von Neumann beschreibt die Von-Neumann-Architektur. Diese ist ein Modell eines Aufbaus des Computers (mit Fokus auf Computer-Komponenten und Interaktionen zwischen ihnen). Heute (2022) ist sie Grundlage für viele Computer.
<gallery>
Zuse-Z4-Totale deutsches-museum.jpg|Die Z4 im deutschen Museum
Von-Neumann Architektur.svg|Schematischer Aufbau der Von-Neumann-Architektur
Modellrechenautomat TH Dresden 1958 TSD.jpg|Ein Rechensystem auf Grundlage der Von-Neumann-Architektur
</gallery>
===1946===
* 14.02.1946: Der {{w|ENIAC}} (''Electronic Numerical Integrator and Computer'') ist der erste elektronische turingmächtige Universalrechner und wird der Öffentlichkeit präsentiert.
<gallery>
Glen Beck and Betty Snyder program the ENIAC in building 328 at the Ballistic Research Laboratory.jpg|Der ENIAC in einem Raum
Classic shot of the ENIAC.jpg|Arbeit mit dem ENIAC
</gallery>
===1947===
* 23.12.1947: Der erste Spitzentransistor von {{w|John Bardeen}}, {{w|William Shockley}} und {{w|Walter Brattain}} wird vorgestellt. Ein Transistor ist ein Schaltelement, das in den 2020ern milliardenfach in CPUs oder GPUs verbaut ist und wenige Nanometer groß ist.
<gallery>
Transistors-white.jpg|Große, mit dem Auge sichtbare Transistoren
Nachbau des ersten Transistors.jpg|Nachbau des ersten Spitzentransistoren
N-Kanal-MOSFET (Schema).svg|Aufbau eines MOSFET-Transistors
</gallery>
===1949===
* Der EDSAC wird fertiggestellt. Der Rechner enthält die Von-Neumann-Architektur und ist zu seiner Zeit ein Hochleistungsrechner. EDSAC steht für '''E'''lectronic '''D'''elay '''S'''torage '''A'''utomatic '''C'''alculator.
<gallery>
EDSAC (10).jpg|Ansicht des EDSAC. Er kann Räume füllen.
EDSAC (25).jpg|EDSAC mit Größenvergleich in Form eines Menschen.
</gallery>
===1950===
* Der britische Informatiker Alan Turing stellt den {{w|Turing-Test}} vor. Hierbei steht eine Person X einer Maschine und einer Person Y gegenüber, wobei Person X zu Beginn nicht weiß, wer die Maschine von den beiden anderen ist. Person X kann das durch Fragen usw. herausfinden. Irrt Person X bei der Identifizierung, hat die Maschine den Turing-Test bestanden.
<gallery>
Turing Test Version 3.svg|Mensch oder Maschine? Diese Frage ist elementar beim Turing-Test
</gallery>
===1951===
* 31.05.1951: Der UNIVAC I wird feierlich zum ersten Mal auf einer Zeremonie verkauft. UNIVAC I steht für ''Universal Automatic Computer I''. Es ist einer der ersten kommerziellen Rechner und ein Digitalrechner.
<gallery>
Museum of Science, Boston, MA - IMG 3163.JPG|Desktop mit UNIVAC-Steuerelementen
UNIVAC I Interior.jpg|Das Innenleben des UNIVAC I
UNIVAC-I-BRL61-0977.jpg|Historische Anwendung des UNIVAC I
Mercury memory.jpg|Der Quecksilberspeicher des UNIVAC I
</gallery>
===1952===
* A. S. Douglas entwickelt für den EDSAC ein Tic-Tac-Toe-Spiel: OXO. Es ist eines der ersten Computerspiele und lässt sich über Nummernschalter und Tastatur steuern.
* Arithmetic Language version 0 (A-0) erscheint. Es soll der erste Compiler der Computerzeit sein. Grace Hopper ist die Entwicklerin.
<gallery>
Oxo.jpg|Nachbildung des Spiels
</gallery>
===1954===
* Der IBM 704 wird vorgestellt. Der raumfüllende Großcomputer war einer der ersten, die Gleitkommaarithmetik beherrschten. Diese ist bis heute relevant und wird in Bezug auf Rechenleistung des Öfteren erwähnt. Der Kernspeicher konnte damals bis zu 144 kiB (147 456 Bytes) fassen, was für kleinere Programme ausreichend war.
<gallery>
IBM Electronic Data Processing Machine - GPN-2000-001881.jpg|Kann mit Bücheregalen konkourrieren: Der IBM 704
</gallery>
===1955===
* 19.03.1955: Die Forschungslabore von Bell präsentieren den ersten digitalen Binärrechner, der Halbleiter als Grundelemente nutzt ({{w|TRADIC}}).
* FLOW-MATIC erscheint. Es ist die erste Sprache für Rechensysteme, die dem Englischen ähnliche Worte gebrauchte. A-0 ist ein Vorgänger.
* Der (magnetische) Kernspeicher kommt langsam auf. Er gilt als "Vorgänger" für RAM-Chips in Mikrocomputern.
* TX-0 (''Transistorized Experimental Computer Zero) wird entwickelt (1956 eingesetzt). Er ist einer der ersten transistorbasierten Computer.
<gallery>
AMPEX computer product division 1973 Magnetic core memory 8192 words of 8 bits here 32768 bits or 32 kBytes.jpg|Magnetspeicher: Riesig, teuer, wenig Speicher
</gallery>
===1956===
* 14.09.1956: Das Festplattenlaufwerk wird vorgestellt. IBM produziert die Erste, die IBM 350 heißt. Sie hat etwa 3,75 Megabyte Speicherplatz und die Abmessungen sind (152 x 172 x 74) cm³. 8800 Zeichen pro Sekunde beträgt der Datentransfer. Heutige (Stand: 2022) Festplatten haben eine Kapazität von (etwas mehr als) 20 Terabyte, also das 5,333333-Millionenfache.
<gallery>
BRL61-IBM 305 RAMAC.jpeg|Rechner IBM 305 mit IBM 350
</gallery>
===1957===
* FORTRAN erscheint. Diese Programmiersprache führt die Paradigmen prozedural, imperativ, strukturiert und objektorientiert.
<gallery>
Fortran logo.svg|Fortran wurde von einem IBM-Mitarbeiter vorangetrieben
</gallery>
===1958===
* 18.10.1958: Tennis for Two erscheint. Das Computerspiel von William Higinbotham wird auf einem Oszilloskop gespielt.
<gallery>
Tennis For Two on a DuMont Lab Oscilloscope Type 304-A.jpg|T4T am Oszilloskop
Tennis For Two in 1958.jpg|Das Spiel bei einer Ausstellung 1958
</gallery>
===1959===
* Der PDP-1 (''Programmed Data Processor 1'') von DEC wird entwickelt. Er gilt als der erste Minicomputer und bietet unter anderem Spacewar!. Er wird mit Lochstreifen, Lichtgriffel, Fernschreiber und Tastatur bedient.
* COBOL erscheint. Es ist eine starke und statische Programmiersprache. COBOL steht für '''Co'''mmon '''B'''usiness '''O'''riented '''L'''anguage. COBOL wird bis in die 2020er hinein genutzt.
<gallery>
PDP-1.jpg|Ansicht des PDP-1
PDP-1 control board.jpg|Steuerelement des PDP-1
Steve Russell-PDP-1-20070512.jpg|Steve Russell bedient den PDP-1
Computer History Museum (2635829142).jpg|Der kreisförmige Bildschirm mit Lichtgriffel
Minskytron-PDP-1-20070512.jpg|Ausgabe am Bildschirm des PDP-1
</gallery>
===1960===
* Ingenieur Mohamed M. Atalla fertigt die ersten ''Metall-Oxid-Halbleiter-Feldeffekttransistoren'' (MOSFETs). Erste Patente stammen aus den 1920-1930ern.
<gallery>
MOSFET_transistors.jpg|Ohne Transistoren geht in der Mikroelektronik (fast) nichts
</gallery>
===1962===
* Q1: Spacewar! wird veröffentlicht. Das von Steve Russell entwickelte Spiel war eines der ersten Computerspiele und auch ein Mehrspieler-Spiel.
<gallery>
Spacewar screenshot.jpg|Spacewar! auf dem PDP-1
Spacewar1.png|Ähnliches Abbild
</gallery>
===1963===
* Der {{w|ASCII}} (American Standard Code for Information Interchange) wird von der ASA gebilligt. Es ist eine Zeichenkodierung.
* Algol 60 wird fertig entwickelt. Es nutzt die ''sequentielle Formelübersetzung''.
* Frank Wanlass lässt sich die Technologie des ''Complementary metal-oxide-semiconductor'' patentieren. CMOS sind elementar für die Mikroelektronik und lassen sich oft (in Varianten) in Mikroprozessoren finden.
<gallery>
USASCII code chart.png|Eine ASCII-Tabelle
Inverter1.svg|Ein CMOS-Inverter
</gallery>
===1965===
* Dendral (Dendritic Algorithm) beginnt. Es handelt sich hier um eines der ersten Projekte in Bezug auf künstliche Intelligenz. Mit ihm wollte man wissenschaftlich arbeiten und mehr über KI herausfinden.
===1966===
* {{w|ELIZA}} wird entwickelt. Es handelt sich um eine Art Chatbot (Programm der linguistischen Datenverarbeitung). 2023 hielten in einem Text ELIZA als eher menschlich als das kostenfreie ChatGPT.<ref>https://www.heise.de/news/Turing-Test-Studie-Ur-Chatbot-Eliza-aus-den-1960ern-schlaegt-GPT-3-5-9546845.html</ref>
<gallery>
ELIZA conversation.png|Kommunikation mit ELIZA
</gallery>
===1967===
* Mit der "Brown Box" wird der Prototyp einer Spielekonsole für den Heimfernseher gezeigt. Das Projekt mündet später in die Magnavox Odyssey. Sie enthält Transistoren.
<gallery>
Brown Box.jpg|Die Brown Box. Auch in den 2020ern greifen Spielekonsolen unter anderem auf Fernseher als Ausgabemedien zurück
</gallery>
===1969===
* 08.1969: Das Mehrbenutzer-Betriebssystem für EDV-Systeme Unix von Bell Laboratories wird entwickelt. Es bietet heute (2022) die Basis für Linux- und MacOS-Systeme.
* 20.07.1969: Apollo 11 landet auf dem Mond. Für dieses Vorhaben ist viel Programmierung und Code notwendig. Für Navigation und mehr ist die Wissenschaftlerin Margaret Hamilton zuständig, die später ausgezeichnet wird.
* 29.10.1969: Über das ARPANET (Advanced Research Projects Agency Network) werden zum ersten mal Daten übertragen. Das ARPANET gilt als eines der ersten Computer-Netzwerke und ist Vorfahre des World Wide Web.
* Die Diskette wird vorgestellt. Sie hat 80 bis 3250 KiB Speicherkapazität. Sie ist bis etwa Windows XP beliebt, wird später jedoch aufgrund der geringen Speicherkapazität nicht mehr in der breiten Anwendung genutzt.
<gallery>
Unix history-simple.svg|Zeittafel von Unix
IBM Blue Gene P supercomputer.jpg|Unix findet meist hier Anwendung: In Supercomputern
Apollo 11 insignia.png|Logo von Apollo 11
Floppy disks - 8 inch, 5.25 inch, 3.5 inch (17361863025).jpg|Disketten mit verschiedenen Formfaktoren
MS Office 4.3 (de) (1) JD.jpg|Ein Problem: Die begrenzte Speicherkapazität macht bald viele Installationsmedien nötig. Fehlt eine Diskette, hat man ein Problem
</gallery>
===1971===
* 10.1971: Ray Tomlinson verschickt die erste Email.
* 15.11.1971: Der 4-Bit-Mikroprozessor Intel 4004 wird produziert. Er ist einer der ersten vertriebenen Mikroprozessoren. Seine Lithografie beträgt 10 µm und taktet in 500 bis 740 Kilohertz. Der Prozessor nutzt PMOS (''p-type metal-oxide semiconductor'') und enthält 2300 Transistoren. Prozessoren um 2022 haben über eine Milliarde Transistoren.
* Mit dem {{w|ALOHAnet}} gelingt eines der ersten drahtlosen Kommunikationsnetzwerke. Später wird das WLAN (Wireless local area Network) genutzt. WLAN-Chipsätze findet sich mit Stand 2022 in etlichen mobilen, aber auch einigen stationären Geräten.
<gallery>
Email (246377) - The Noun Project.svg|"Sie haben Post" - zumindest digital
Ray Tomlinson.jpg|Digitale Kommunikation in der Geburt: Der Verfasser der ersten Email
Intel C4004.jpg|Der Intel C4004 - sehr beliebt (weiße Keramik)
Intel D4004.jpg|Der Intel D4004 (graue Keramik)
Intel P4004.jpg|Der Intel P4004 (schwarzer Kunststoff)
4004 dil.svg|Belegung der Pins
Wifi (89622) - The Noun Project.svg|Hier gibt's Netz
</gallery>
===1972===
* Der Intel 8008 erscheint. Es ist ein 8-Bit-Prozessor und die erste Von-Neumann-Rechneneinheit von Intel. Der Prozessor wird bis 1983 produziert. Er taktet in 500-800 KHz, Fertigungsgröße ist 10 µm. Die Technik ist PMOS und hat 3500 Transistoren. Er schafft 0,05 Millionen Instruktionen pro Sekunde und hat 16 KiB adressierbaren Speicher.
* Die imperative und strukturierte Programmiersprache C erscheint. Von ihr stammen Sprachen wie C++, C#, D, Java oder PHP.
* 29.11.1972: Pong erscheint. Das monochrome Spiel ist eines der ersten populären Videospiele. Es wurde von Atari entwickelt.
<gallery>
Intel C8008.jpg|Der Intel C8008
Intel D8008.jpg|Der Intel D8008
Intel 8008 arch.svg|Schaltbild des Intel 8008
C1stEdition.svg|Logo von C
Pong.svg|Grafische Benutzeroberfläche von Pong
Pong Arcade.jpg|Pong auf einem Automaten
TeleGames-Atari-Pong.png|Konsole für Pong
</gallery>
===1973===
* 03.04.1973: Martin Cooper tätigt den ersten Anruf über ein Mobilgerät, das als Mobiltelefon-Prototyp bezeichnet wird. Er gilt als "Vater" des Mobiltelefons.
* 10.1973: Die Magnavox Odyssey erscheint. Es ist eine der ersten Spielekonsolen, die man an den Fernseher anschließt.
* Der Grundriss des Ethernets ("Äther-Netzes") wird erwähnt. Das Ethernet ist die Technik hinter der Datenübertragung mit LAN-Kabeln.
<gallery>
2007Computex e21Forum-MartinCooper.jpg|Damals noch unhandlich: Das Mobiltelefon
Magnavox-Odyssey-Console-Set.jpg|Die Konsole
Magnavox Odyssey Logo.svg|Das Logo
Electronics---Connector---RJ-45-Male---Detailed---(Gentry).jpg|Dieses Kabel steht in Verbindung zu Ethernet
</gallery>
===1974===
* Der Intel 4040 erscheint. Es ist ein 24-pin-4-Bit-Mikroprozessor und der Nachfolger des 4004. Er nutzt PMOS, hat eine Lithografie von 10 µm, enthält 3000 Transistoren, taktet in 500-740 kHz. Die Befehlszahl wurde auf 60 erhöht.
* CP/M (Control Program for Microcomputers) wird von Digital Research Inc. veröffentlicht. Das OS ist unter anderem für Intel 8080 in der Anwendung. Ab 2022 steht das Werk unter Public Domain.
* SQL (Structured Query Language) erscheint. Es ist eine Sprache für Datenbanken.
* {{w|Bravo (Textverarbeitung)}} ist eines der ersten Programme, das das Prinzip des ''WYSIWYG'' (What you see is what you get) benutzt. Das Prinzip zeigt einen Inhalt in der Bearbeitung so an, wie er auch für alle anderen sichtbar sein wird. Das Prinzip ist meist in Textvearbeitungsprogrammen zu finden.
<gallery>
Intel C4040.jpg|Der Intel C4040
KL Intel D4040.jpg|Der Intel D4040
KL Intel P4040.jpg|Der Intel P4040
CPM-86.png|Screenshot von CP/M
CPM-Manual.jpg|Eine Bedienungsanleitung für CP/M
DEC VT180.jpg|Ein Computer, der CP/M nutzt
</gallery>
===1975===
* Der '''Utah Teapot''' wird von Martin Newell modelliert und dient als eines der bedeutendsten 3D-Modelle zum Zwecke des Renderns
* Der MITS Altair 8800 erscheint. Er gilt als einer der ersten Personal Computer<ref>https://www.hnf.de/dauerausstellung/ausstellungsbereiche/computer-fuer-alle-1980-2000/die-geburt-des-pc-aus-der-garage-in-die-welt.html</ref>
* Der MOS (Technology) 6502 erscheint als 8-Bit-Mikroprozesor. Er wurde als preisgünstige CPU in vielen frühen Heimcomputern verbaut.
<gallery>
Living_Computers_-_Altair_8800_%2839802981903%29.jpg|Die Funktionalität war damals noch relativ übersichtlich
Utah teapot simple 2.png|Der "Utah Teapot"
MOS6502.jpg|Eine Subvariante des MOS 6502
</gallery>
===1976===
* Der Supercomputer Cray 1 wird in Betrieb genommen. Es ist der erste Supercomputer von Cray. Cray-1A wog über 5,5 Tonnen. Er taktet mit 80 Megahertz, hat 8 Mebibyte RAM, und hat eine Leistung vom 80 MegaFLOPS. Der Stromverbrauch beträgt 115 Kilowatt.
<gallery>
CRAY-1-Logo.jpg|Logo der Cray-1
EPFL CRAY-I 2.jpg|Das Kontrollelement der Cray-1
Cray-1-deutsches-museum.jpg|Die Cray-1 im Deutschen Museum
</gallery>
===1977===
* Das Atari Video Computer System (Atari 2600) erscheint in den USA. Die Spielkonsole ist eine der bedeutendsten Konsolen in kultureller Sicht und hat die Heimunterhaltung maßgeblich verändert.
* Der Commodore PET (Personal Electronic Transactor) 2001 erscheint. Er ist einer der ersten PCs im Engeren Sinne mit Bildschirm und Diskettenlaufwerken und mehr. Er ist aufgrund des Preises einer der ersten erschwinglichen und verbreiteten PCs. Die Ära der PCs beginnt also in den 1970ern.
<gallery>
Atari-2600-Four-Switch-Black-Console-01.jpg|Ein Modell der Konsolenreihe. Aus heutiger Sicht mit unfassbar niedrigen Hardwarespezifikationen.
Commodore 2001 Series-IMG 0448b.jpg|Etwas unhandlicher als ein Haustier: Der Commodore PET 2001
</gallery>
===1978===
* Der Volkseigene Betrieb Kombinat Robotron produziert das {{w|Mikrorechensystem K 1520}}. Es nutzt ein 8-Bit-Mikroprozessorsystem.
* StorageTek bringt eine der ersten {{w|Solid State Drive}}s raus.
<gallery>
Robotron K2521 (012-7100) ZRE.jpg|Platine K 2521 für K 1520 mit CPU MME UB 880 D @ 2,4576 MHZ
Robotron k8915.jpg|Der Robotron K 8915 auf Basis des K 1520
</gallery>
===1979===
* Das Atari Video Computer System erscheint in Deutschland. Es ist eine der ersten Spielkonsolen von Atari.
* Das sogenannte Usenet entsteht. Es ist ein elektronisches Netzwerk, das neben dem World Wide Web existiert.
* Visicalc erscheint für den Apple II. Es ist eines der ersten kommerziellen Tabellenkalkulationsprogramme.
<gallery>
Atari, Inc. logo (1973).svg|Logo von Atari
Atari-2600-Light-Sixer-FL.jpg|Das Atari 2600 (VCS)
Visicalc logo.svg|Logo von Visicalc
Visicalc.png|Screenshot von Visicalc
</gallery>
===1980===
* 22.05.1980: Pac-Man erscheint in Japan. Das Spiel erreicht später Kultstatus und einen sehr hohen Bekanntheitsgrad.
* Die strukturierte Programmiersprache {{w|Ada (Programmiersprache)}} erscheint. Namenspatronin ist Ada Lovelace.
* Die allererste Festplatte mit einer Speicherkapazität von 1 Gigabyte erscheint unter dem Namen ''IBM 3380''. Dieses Speicherelement war jedoch so groß wie ein Kühlschrank und kostete 81.000 bis 142.000 Dollar.<ref>https://www.computerweekly.com/de/definition/Gigabyte-GB-GByte</ref>
<gallery>
Paku-paku5-dos.png|Ähnliche Version von Pac-Man
Ada horizon green logo with slogan.svg|Logo von Ada
IBM3380DiskDriveModule.agr.jpg|Ein Bauelement des IBM 3380
</gallery>
===1981===
* 12.08.1981: MS-DOS, eines der populärsten Disk Operating Systems, erscheint.
* Das {{w|BIOS|Basic Input/Output System}} wird eingeführt. Es bildet die Firmware ("Basis") für etliche PCs.
<gallery>
Msdos-icon.svg|Logo von MS-DOS
MS-DOS Deutsch.png|Screenshot von MS-DOS
Datei:Award BIOS setup utility.png|So sieht ein typisches BIOS-Menü (im DOS-Stil) aus
</gallery>
===1982===
* 19.09.1982: Der Informatikprofessor {{w|Scott E. Fahlman}} schlägt aus Gründen der Eindeutigkeit das Emoticon vor. Durch diese Zeichengruppen lassen sich an der jeweiligen Textstelle beabsichtigte Emotionen darstellen.
* Der Commodore 64 erscheint. Er wird umgangssprachlich "Brotkasten" genannt. CPU: MOS 6510/8500 @ 1,023 MHz (NTSC) / 0,985 MHz (PAL). RAM: 64 KiB RAM, Grafik: VIC II (320 x 200, 16 Farben, Sprites). OS: Commodore Basic V2, GEOS 64.
* Die {{w|Compact Disc}} erscheint auf dem Markt. Sie hat einen Durchmesser von 12 cm und etwa 650 MB Speicher.
<gallery>
Commodore 64 logo-3-17.svg|Ein Logo des C64
Commodore 64 Splash.png|Benutzeroberfläche des C64
Commodore-64-Computer-FL.png|Der C64
Compact Disc wordmark.svg|Logo der CD
CD autolev crop.jpg|Unterseite einer CD
</gallery>
===1983===
* 08.03.1983: Mit dem IBM Personal Computer XT erscheint einer der ersten PCs, der eine eingebaute Festplatte hat. Frühere Rechner hatten dies nicht. So war mit MS-DOS 1.x (1981) nicht vorgesehen, eine Installation dieses Betriebssystems durchzuführen. Vielmehr wurde eine Diskette mit MS-DOS eingeschoben, und mit einer zweiten Diskette Daten gespeichert oder gelesen. Die HDD des IBM PC XT ist 10 MB groß.
* Apple Lisa erscheint. Der Computer ist einer der ersten Rechner mit Maus als Eingabegerät und einer grafischen Benutzeroberfläche, damals noch monochrom.
* Mit Lotus 1-2-3 erscheint es der ersten Tabellenkalkulationsprogramme für PCs. Damals galt das Programm als rechenaufwändig.
<gallery>
IBM PC XT color.jpg|Heute selbstverständlich: Ein PC mit Festplatte
IBM model F 3887360487 ca719998f0 o.jpg|Das Eingabegerät des IBM PC XT
Apple Lisa.jpg|Lisa mit Festplatte über dem Bildschirm
Lotus-123-3.0-MSDOS.png|Tabellen in schlichter Form (Lotus 1-2-3)
</gallery>
===1984===
* Das Softwarepaket '''<math>\mathrm{L\!\!^{{}_{A}} \!\!\!\!\!\;\; T\!_{\displaystyle E} \! X}</math>''' wird veröffentlicht.
* Mit dem {{w|Apple Macintosh}} erscheint einer der ersten Mikrocomputer mit GUI und größeren Absatzzahlen. Der Name ist von McIntosh abgeleitet, einer Apfelsorte. Spätere Modelle heißen meist nur noch ''Mac''.
* Der Robotron Z 9001 erscheint. Es ist ein preisgünstiger Heimcomputer, der hauptsächlich auf Textausgabe setzt.
* Der Videocodec {{w|H.120}} wird veröffentlicht. Er ist einer der ersten Videocodecs für Computer. Er selbst wurde nicht erfolgreich, legte aber die Grundlagen für folgende Kodierungsstandards.
<gallery>
LaTeX project logo bird.svg|Logo des LateX-Projektes
Macintosh 128k transparency.png|Der Macintosh 128k mit GUI
Robotron KC 87.jpg|Der Robotron KC 87 (ähnlich zum Z 9001)
</gallery>
===1985===
* 13.09.1985: {{w|Super Mario Bros.}}, das erste Spiel der Super-Mario-Reihe erscheint in Japan. Super Mario ist eine der erfolgreichsten Videospielreihen.
* 20.11.1985: {{w|Windows 1.0}}, das erste Microsoft-Windows-Betriebssystem, erscheint.
* Die Intel-80386-Serie geht in Serie und wird bis 2007 produziert. Es ist eine x86-CPU mit 32-Bit-Architektur. ''x86'' ist von 80x86 abgeleitet, wobei das x für die Prozessorengenerationen von Intel steht (80186, 80286, 80386, ...).
* Durch Programmierfehler gibt es von 1985-1987 Schäden an Leib und Leben durch {{w|Therac-25}}. Hier wurden Menschen mit Überdosen und fehlenden Sicherungsmaßnahmen geschädigt, 3 Menschen sterben.
{| class="wikitable"
|+ Systemvoraussetzungen für Windows 1.0
|-
! Aspekt !! Wert
|-
| CPU || Intel 8088
|-
| RAM || 256 KiB
|-
| Laufwerke || Zwei Diskettenlaufwerke
|}
<gallery>
Super Mario Bros. Logo.svg|Logo von Super Mario Bros.
Windows logo and wordmark - (1985-1989).svg|Logo von Windows in den 1980ern
KL Intel i386DX.jpg|Intel i386 DX
Intel 80386 DX die.JPG|Die des Intel 80386 DX
</gallery>
===1986===
* 21.02.1986: Mit {{w|The Legend of Zelda}} wird die The-Legend-of-Zelda-Reihe eingeführt.
* 01.09.1986: Das Nintendo Entertainment System erscheint in Europa. Es ist eine stationäre Spielkonsole.
* Der sogenannte '''Megachip''' {{w|U61000}} erscheint. Den Namen hat die CPU von ihrem 1-MBit-DRAM-Bauteil. Er wird in der DDR veröffentlicht. Die Strukturbreite beträgt 1,2 µm. Der erste U61000 wird an den Staatsratsvorsitzenden Erich Honecker übergeben.
{| class="wikitable"
|+ Spezifikationen Super Nintendo Entertainment System
|-
! Typ !! Wert
|-
| Release (Europa)|| 01.09.1986
|-
| CPU || Ricoh 2A03 @ 1,77 MHz (PAL) / @ 1,79 MHz (NTSC)
|-
| RAM || 2 kiB, VRAM 2 kiB
|-
| GPU || PPU Ricoh Chip (NTSC: RP2C02, PAL: RP2C07) @ 5,37 MHz bzw. 5,32 MHz, 256x224 Pixel (NTSC), 256x240 (PAL), Farbpalette: 52 Farben, 8x8 Pixel oder 8x16 Pixel Sprites
|-
| Datenträger || Speichermodule
|-
| Controller || NES-Controller
|-
| Verkaufte Einheiten || etwa 61,91 Mio. (bis 30.09.2019)
|-
| Audio || 5 Soundkanäle, 6-Bit-Delta-PCM-Soundkanal und mehr
|-
| Masse || 1,2479 kg
|}
<gallery>
Zelda Logo.svg|Logo der Reihe
Zelda old logo.svg|Logo des ersten Spiels
The Legend of Zelda - Golden Catridge.jpg|Die Cartdridge des Spiels
NES logo.svg|Das Logo des Nintendo Entertainment Systems
NES-Console-Set.png|Das NES mit Controller
Nintendo-Famicom-Console-Set-FL.png|Der Famicom, das japanische Äquivalent
Bundesarchiv Bild 183-1989-0313-123, VEB Carl Zeiss Jena, 1-Megabit-Chip.jpg|Ein historisches Foto des U61000D
Megabit ZMD U61000C.jpg|Die U61000C
Bundesarchiv Bild 183-1989-0406-022, VEB Carl Zeiss Jena, 1-Megabit-Chip.jpg|Der 1-Megabit-Chip mit offener Oberseite
Bundesarchiv Bild 183-1988-0912-400, Berlin, Übergabe der 1-Megabit-Speicherschaltkreise.jpg|Honecker bei einer Vorstellung des U61000
</gallery>
===1987===
* Mit der Conner CP340A-HDD wird der 3,5"-Formfaktor für Festplatten Standard.
* IBM bringt das Personal System/2 in Umlauf. Es ist eine PC-Reihe.
<gallery>
IBM PS2 model 55SX.jpg|Ein PS/2 Rechner: Der PS/2 Model 55 SX
IBM PS2 hiiri.jpg|Eine Maus des PS/2
</gallery>
===1988===
* Die damalige High-End-Workstation {{w|NeXTcube}} erscheint. Er war unter anderem der erste Server des WWW.
<gallery>
NeXTcube.jpg|Der NeXTcube
NeXTcube.jpeg|Arbeitsplatz mit NeXTcube
First Web Server.jpg|Der NeXTcube-Server
NeXTcube motherboard.jpg|Das Mainboard des NeXTcube
</gallery>
===1989===
* 09.12.1989: Windows 2.x erscheint. Visuell hat sich relativ wenig zum Vorgänger verändert. Intern sind jedoch Funktionen für neuere Hardware dabei.
* 1989: Die erste Version von Microsoft Office erscheint. Die Suite ist bis in 2022 hinein relativ beliebt.
* Die vierte Generation der x86-CPUs, {{w|Intel 80486}} geht in Serie und wird bis 2007 produziert.
<gallery>
Win211StartBildschirm.png|Bootlogo von Windows 2.11
80486 open.jpg|Intel 486DX 33 MHz mit sichtbarem Die von unten
486 Prozessoren von AMD Cyrix IBM Intel ST Texas Instruments.jpg|Verschiedene 486er
</gallery>
===1990===
* 22.05.1990: Windows 3.0 erscheint. Das Update 3.11 ist jedoch beliebter. Visuell hebt sich Windows 3.0 deutlich von seinen Vorgängern ab und nutzt einige Funktionen, die es heute noch gibt, wie einen dem heutigen Desktop ähnlichen Desktop.
* Die proprietäre Software Adobe Photoshop erscheint und ist eine der verbreitesten Software der Bildbearbeitung. Im strengeren Sinne bezeichnet "Photoshop" nur die Softwaremarke von Adobe.
<gallery>
Windows 3.0 29 12 2020 11 03 55 GER.png|Windows 3.0-Bootscreen
Adobe Photoshop CC icon.svg|Logo von Adobe Photoshop
</gallery>
===1991===
* 20.02.1991: Die starke und dynamische Programmiersprache Python erscheint.
* 17.09.1991: Der Linux-Kernel wird veröffentlicht. Er dient als Grundlage für die vielen Linux-Derivate und -Distributionen. Dank der Open-Source-Lizenz GPLv2 konnte Linux sich so weit verbreiten. Linus Torvalds ist maßgeblich an Linux beteiligt.
* 10.1991: Der Unicode-Standard wird in der Version 1.0.0 veröffentlicht (beginnend mit 7.161 Zeichen). Mit Version 14 von 2021 enthält dieser Standard 144.697 Zeichen. Ziel ist ein großer Zeichensatz, den die Computer darstellen können.
* Das World Wide Web wird der Öffentlichkeit vorgestellt. Maßgeblich beteiligt war Tim Berners-Lee. Da aufgrund rechtliche Beschränkungen wie Patentschutz oder Lizenzierungen verzichtet wurde, kann das WWW zu seiner heutigen Größe wachsen. Es wird als eines der weitreichendsten Erfindungen der Menschheit angesehen (das lässt sich dadurch begründen, da ohne eine Vernetzung von Rechnern die heutige Zeit grundlegend aussähe).
* Das verlustbehaftete Audioformat MP3 wird vertrieben. In den 2010ern erlosch der Patentschutz. MP3-Dateien sind mitunter die häufigsten als Audioformat, neben WAV und anderen.
* Die ersten 1-GB-Festplatten für Heimrechner erscheinen. Sie kosten etwa 3000 $.<ref>https://www.computerweekly.com/de/definition/Gigabyte-GB-GByte</ref>
* Intel stellt die Version 1.0 von PCI (Peripheral Component Interconnect) vor. Es ist ein Bus-Standard von Peripheriegeräten. Grafikkarten der 2010er und 2020er nutzen den Nachfolger PCI Express.
* Das Portable Document Format (PDF) wird aus dem Hause Adobe initiiert. Es ist ein Dokumentenformat, das später ein offener Standard wurde und starke Verbreitung findet. Es teilt Eigenschaft wie die Speicherung von Vektorinhalten. Andere Dokumentenformate sind EPUB, CBZ, etc.
<gallery>
Python logo and wordmark.svg|Logo von Python
Tux.svg|Tux, das Linux-Maskottchen
Linux 3.0.0 boot.png|Bootscreen des Kerns
New Unicode logo.svg|Neueres Logo von Unicode
WWW logo by Robert Cailliau.svg|Drei Buchstaben, nahezu jede(r) weiß, was gemeint ist
NeXTcube first webserver.JPG|Der mitunter erste Webserver. Heutige Server füllen meist ganze Hallen
Tim Berners-Lee CP.jpg|Er trieb die Entwicklung voran und gab das WWW frei: Tim Berners-Lee
Mp3 format logo.svg|MP3-Logo
PCI Slots Digon3.JPG|Übliche PCI-Slots
PDF file icon.svg|Logo für PDF-Dateien
</gallery>
===1992===
* 18.07.1992: Das erste Bild wird ins Web hochgeladen. Es heißt "Les Horrible Cernettes".
* 15.08.1992: Das Super Nintendo Entertainment System erscheint in Deutschland. Es ist der Nachfolger des NES.
* 03.12.1992: Die erste SMS-Nachricht wird von Neil Papworth verschickt. Der Inhalt ist "Merry Christmas".
* Der freie Webbrowser Lynx erscheint. Es ist einer der ersten Webbrowser und einer, der rein textbasiert ist, also keine Multimediadateien anzeigt.
* Prozessoren der Pentium-1-Familie gehen in Serie (''80586''). Sie werden bis 1999 produziert. Pentium-Prozessoren werden bis in die 2010er entwickelt und hergestellt.
* Die Hypertext Markup Language, eine Auszeichnungssprache für das World Wide Web, entsteht.
{| class="wikitable"
|+ Spezifikationen Super Nintendo Entertainment System
|-
! Typ !! Wert
|-
| Release (Deutschland)|| 15.08.1992
|-
| CPU || 16-Bit Ricoh 5A22 (65C816-Kern) @ 3,579545 MHz
|-
| RAM || 128 KiB RAM, 64 KiB VRAM
|-
| GPU || 2 Picture Processing Units, Darstellung: 32768 Farben, 224 oder 239 Zeilen
|-
| Datenträger || Speichermodule
|-
| Controller || SNES-Controller
|-
| Verkaufte Einheiten || etwa 49,10 Mio. (bis 30.06.2016)
|-
| Audio || 8-Bit-Sony-SPC700-CPU mit angebundenem Sound-DSP,
|}
<gallery>
Lynx Browser 2.png|Schlicht, aber ziemlich kompatibel: Lynx
Super Famicom logo.svg|Logo des SNES
SNES logo.svg|Textzug des SNES
Wikipedia SNES PAL.jpg|Das SNES
Nintendo-Super-Famicom-Set-FL.png|Das SNES in Japan
SNES-Mod1-Console-Set.png|Nordamerikanisches SNES
SuperFamicom jr.jpg|Super Famicom Jr.
SNES-Model-2-Set.jpg|Nordamerikanisches SNES (neuer)
SMS test.jpg|Damals musste man sich kurz halten: Mehr als 160 Zeichen sieht eine SMS-Nachricht nicht vor
PENTIUMFAMILY.JPG|CPUs der Pentium-Reihe
HTML.svg|Beispiel für HTML-Code
</gallery>
===1993===
* 23.01.1993: Der NCSA Mosaic-Webbrowser erscheint. Die Lebenszeit des Browsers ist kurz; im Januar 1997 erscheint die bis dato letzte Version: 3.0
<gallery>
NCSA Mosaic Browser Screenshot.png|Die Benutzeroberfläche des Browsers NCSA Mosaic
</gallery>
===1994===
* amazon geht online. Der Fokus liegt zu Beginn auf Büchern, nun ist es ein Cloud-Anbieter und ein Faktor im Onlinehandel. Kritisiert wird, dass amazon ein Monopol darstellt und viel Macht hat.
* 16.08.1994: Der {{w|IBM Simon Personal Computer erscheint}}. Das Gerät gilt als eines der ersten "Smartphones".
* 13.10.1994: Der {{w|Netscape Navigator}} erscheint. Er ist zum Zeitpunkt relativ beliebt, verliert jedoch bald wieder an Bedeutung. Heute wird er nicht mehr weiterentwickelt.
* Der Quick response code ({{w|QR-Code}}) wird eingeführt.
<gallery>
Amazon logo.svg|Logo von amazon
Day 1 Tower Seattle WA Jan 17.jpg|Day 1 Tower von amazon
IBM_Simon_Personal_Communicator.png|Ähnelt in einigen Eigenschaften dem modernen Smartphone
Netscape icon.svg|Logo des Netscape Navigators
QR deWP.svg|Ein QR-Code
</gallery>
===1995===
* 02.01.1995: Die freie 3D-Grafiksuite Blender erscheint.
* 08.06.1995: Die Skriptsprache {{w|PHP}} erscheint. Sie findet hauptsächlich bei Webanwendungen Anwendung.
* 14.08.1995: Mit dem Virtual Boy erscheint eines der ersten Virtual-Reality-Gerätschaften. Erfolgreich wird diese Apparatur jedoch nicht.
* 24.08.1995: Windows 95 erscheint. Mit diesem Betriebssystem kommt der endgültige Durchbruch für die Windows-Betriebssystemfamilie. Der Aufbau ähnelt noch dem heutigen Windows 11. Es hat eine Taskleiste, ein Startmenü, Drag&Drop, Registry und mehr.
* Die Skriptsprache für dynamisches HTML {{w|JavaScript}} erscheint.
* Die objektorientierte Programmiersprache Java erscheint. Sie ist stark und statisch. Sie kommt häufig im Schulunterricht (Informatikunterricht) vor.
<gallery>
Screenshot Blender 2.91.0 GER 20210107.png|Benutzeroberfläche von Blender
PHP-logo.svg|Logo von PHP
Virtual-Boy-Set.png|Der Virtual Boy
Microsoft Windows 95 logo with wordmark.svg|Windows-95-Logo mit einem "fliegenden Fenster"
Windows 95 - installation disk 3 1⁄2-inch, floppy disk.jpg|Windows-95-Installation geschah über Disketten...
Windows 95 & Microsoft Plus CD Room de instalación.jpg|...oder einer CD
Ibm300pl.jpg|Ein Arbeitsplatz mit Windows 95
</gallery>
===1996===
* Der Schachcomputer {{w|Deep Blue}} von IBM besiegt als ersten Rechner den damaligen Schachweltmeister Garry Kasparov in einer Partie Schach.
* Ab etwa 1996 halten die ersten RAM-Riegel mit SDRAM in PCs Einzug.
* 26.02.1996: Der WDR ComputerClub berichtet über die Förderung der Telearbeit in Saugendorf. Bis Telearbeit (oder heutzutage eher "Homeoffice" genannt) in Deutschland einigermaßen üblich wird, sollen noch mindestens 2 Jahrzehnte vergehen.
* 29.07.1996: Windows NT 4.0 erscheint. Es gibt die Versionen Workstation und Server und ähnelt visuell Windows 95.
* Microsoft initiiert {{w|Core fonts for the Web}}, um die Nutzung einiger Schriftarten zu standardisieren. Das Projekt wird 2002 beendet.
<gallery>
128 MiB DIMM 168 PIN RAM (Vorderseite) 20220124.png|Einer der ersten RAM-Riegel mit SDRAM: Mit gerade einmal 128 MiB Speicher und einer Taktung von 133 MHz
Say hello to Deep Blue (2586059148).jpg|Ein ähnliches Modell zum originalen Deep Blue
2021 - Q&A DG1 1524 (51654553854).jpg|Musste sich damals geschlagen geben: Garry Kasparov
Saugendorf Ortseingang.jpg|Saugendorf – wirkt sehr ländlich, aber war technisch der Zeit voraus
Windows NT logo.svg|Logo von Windows NT 4.0
Windows NT 4.0 Workstation logo.svg|Windows-NT-4.0-Logo der Workstation-Version
Windows NT 4.0 Workstation – niebieski ekran śmierci.png|BSoD unter Windows NT 4.0
</gallery>
===1997===
* 01.03.1997: Der {{w|Nintendo 64}} erscheint für den europäischen Markt.
{| class="wikitable"
|+ Spezifikationen N64
|-
! Typ !! Wert
|-
| Release (Europa)|| 01.03.1997
|-
| CPU || 64-Bit MIPS R64300i RISC @ 93,75 MHz (125 MIPS)
|-
| RAM || 4 MiB Rambus-DRAM @ 500 MHz (ohne Expansion Pak)
|-
| GPU || 64-Bit RCP @ 62,5 MHz, 256x224 bis 768x576 Pixel
|-
| Datenträger || Cartridges mit 64 MB (ROM)
|-
| Controller || Nintendo-64-Controller
|-
| Verkaufte Einheiten || 32,93 Mio.
|-
| Audio || ADPCM, 16-Bit-Stereo, Dolby Surround
|-
| Masse || 1,1 kg
|}
<gallery>
N64-Console-Set.png|Nintendo 64 mit Controller
N64-cartridge-chip side-wo heatsink.jpg|Cartridge des N64
N64-Controller-Gray.jpg|Ein Controller des N64
</gallery>
===1998===
* 25.06.1998: {{w|Windows 98}} erscheint. Visuell gibt es relativ wenige Neuerungen, intern mehr Sicherheit und aktuellere Treiber für neuere Hardware. Jedoch lässt sich mit einem Trick die Passworteingabe beim Einloggen umgehen.
* 07.1998: Intel bringt die Prozessormarke "Xeon" auf dem Markt. Die Prozessorserie soll das vertikale Segment der Server bedienen. Diese CPUs sind meist mit vielen Kernen bestückt, die relativ niedrig takten. Darüber hinaus gibt es Zusatzmechanismen und -funktionen, um den dauernd laufenden Server gerecht zu werden.
* 12.1998: Der IEC führt Binärpräfixe für Einheiten der Datenmenge ein. Diese heißen etwa "Kibi-", "Mebi-" oder "Gibi-". Zur Basis wird die 2 genommen. Diese sind Teil des IEC-80000-13-Standards. Analog zu diesen gibt es die SI-Präfixe "Kilo-", "Mega-", "Giga-" und weitere zur Basis 10. Um Verwechslungen zwischen den Basen 2 und 10 zu vermeiden, wurden die Binärpräfixe eingeführt. Jedoch werden bis in die 2020er die Präfixe und Bezeichnungen durcheinandergeworfen, so nutzen viele Menschen und auch Microsoft Windows fälschlicherweise etwa das "Gigabyte" für 1024 "Megabyte". Richtig wäre das Gibibyte für 1024 Mebibyte.
* Intel veröffentlicht das {{w|Unified Extensible Firmware Interface}}. Es wurde vor allem in den 2010ern populärer.
<gallery>
Microsoft Windows 98 logo with wordmark.svg|Windows-98-Logo mit einem "fliegenden Fenster"
CD Room de instalación de Windows 98.jpg|Ein Windows-98-Installationsmedium
Dell Precision 620MT - 2x PIII - Windows 98 - Work.jpeg|Ein Arbeitsplatz mit Windows 98
Intel-Xeon-Badge-2024.jpg|Logo der Xeons ab 2024
Kleiner, leistungsfähiger Computerr zum Selbermachen (极客湾Geekerwan) 21.png|Xeons mit 28 Kernen oder mehr sind keine Seltenheit (mehr)
</gallery>
===1999===
* 23.12.1999: Die NVIDIA GeForce 256 erscheint.
* Die Entwicklung der grafischen Benutzeroberfläche für Linux {{w|Gnome}} beginnt.
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce 256 DDR<ref>https://www.techpowerup.com/gpu-specs/geforce-gtx-280.c216</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 23.12.1999
|-
| Plattform || GeForce 256
|-
| Generation || GeForce 256
|-
| Architektur || Celsius
|-
| GPU || NV10
|-
| Die-Größe || 1,39 cm²
|-
| Baugröße || 220 Nanometer
|-
| Transistormenge || 17 Millionen
|-
| Slotbreite || 1 Slot
|-
| Pixelshader || 4
|-
| Texture Mapping Units || 4
|-
| Render Output Units || 4
|-
| Grafikspeicher || 32 MiB
|-
| Grafikspeichertyp || DDR
|-
| Busbreite || 128 bit
|-
| Schnittstelle || AGP 4x
|-
| Basistakt || 120 MHz (Memory: 150 MHz)
|-
| Bandbreite Speicher || 4,8 GB/s
|-
| Thermal Design Power || ???
|-
| Anschlüsse || 1x VGA
|-
| DirectX-Version || 78.0
|-
| OpenGL-Version || 1.2
|-
| OpenCL-Version || -
|-
| Shader-Version || -
|-
| Vulkan-Version || -
|-
| Pixelfüllrate || 480 Megapixel/Sekunde
|-
| Texturrate || 480 Megatexel/Sekunde
|-
|}
<gallery>
VisionTek GeForce 256.jpg|Die Karte der GeForce 256 DDR
Gnomelogo.svg|Logo von Gnome
GNOME 1.0 (1999, 03) with GNOME Panel 1 and File Manager.png|Screenshot mit GNOME 1
</gallery>
===2000===
* Der E-Mail-Wurm "I love you" verbreitet sich.
* 01.01.2000: Der Year-2K-Bug ereignet sich, jedoch schwächer als angenommen.
* 17.02.2000: Windows 2000 erscheint. Aufgrund der hohen Hardwareanforderungen konnten zum Release nicht alle umsteigen. Es ist das erste Microsoft Windows, das keine vorherige MS-DOS-Installation benötigt.
* 14.09.2000: Windows ME erscheint. Es ist das letzte OS, das aus der Windows-9x-Linie stammt und auf MS-DOS setzt. Das OS kommt in die Kritik, weil es instabil ist und oft abstürzt. ''ME'' steht für '''Millennium Edition'''.
<gallery>
Loveletter-wurm.png|Email mit dem schädlichen Skript
Bug de l'an 2000.jpg|Nach 1999 kommt 1900
Microsoft Windows 2000 wordmark.svg|Windows 2000
Windows 2000 SP4 install disc (French).jpg|Installationsmedium von Windows 2000
CHT public telephone using Windows 2000 Professional (5983279).jpg|Vor XP war manchmal Windows 2000 als embedded OS unter der Haube
Microsoft Windows Me logo.svg|Logo von Windows ME
Unopened boxes of Microsoft Windows Me and Corel WordPerfect 8.jpg|Damals konnte (oder musste vielmehr) man noch Installationsmedien für Betriebssysteme im Handel vor Ort kaufen
</gallery>
==21. Jahrhundert==
Mit dem 21. Jahrhundert tut sich in der Computertechnik viel, aber es gibt auch etliche Herausforderungen. So müssen Maßnahmen im Umweltschutz und Klimaschutz auch in der IT vonstatten gehen. Dazu gehört, Strom für EDV-Systeme aus grünen Quellen zu beziehen, und etwa Serverwärme weiterzunutzen. Ein Problem durch IT-Technik ist jedoch das Schürfen von Kryptowährungen. Aufgrund der Blockchains und anderer kryptografischer Techniken ist viel Rechenleistung nötig. Eine weitere Challenge ist die Physik. So lassen sich Bauelemente wie Transistoren in der Strukturbreite nicht beliebig verkleinern. Man sagt, dass bei 2 Nanometern quantenphysikalische Mehaniken greifen. Die Fertigungsgröße von Transistoren in 2022 liegt bei etwa 4-6 Nanometern, wobei sich das nicht auf tatsächliche Abmessungen von Bauteilen wie Transistoren bezieht (die eher bei 75 nm liegen).
Auch ist das {{w|Mooresches Gesetz|Mooresche Gesetz}} nicht mehr aufrechtzuerhalten. Dies betrifft die Kapazität von Festplatten und CPUs. So gibt es 1983 die erste Festplatte im PC mit 10 Megabyte. 2001/2002 gibt es die erste 100-Gigabyte-Festplatte, 2007 die erste 1-Terabyte-Festplatte, 2014 die erste 8-Terabyte-Festplatte und 2022 die erste 22-Terabyte-Festplatte. Die Daten beziehen sich jeweils auf den Endmarkt (Endkundschaft). Daraus ergibt sich: Faktor 10000 in 18-19 Jahren (1983-2002), Faktor 10 in 6 Jahren (2001-2007), Faktor 8 in 7 Jahren (2007-2014) und Faktor 2,75 in 8 Jahren (2014-2022).
Weitere Aspekte sind die Knappheit und politische Verwerfungen. Durch gestörte und eingeschränkte Produktionswege (von Rohstoffabbau über die Fertigung der Endprodukte bis hin zur Auslieferung) werden Produkte weniger und teurer. Grund sind unter anderem die COVID-19-Pandemie und politische Spannungen.
Zum Ende des Jahrhunderts sind Technologien und Leistungen zu erwarten, die heute (2022) weder abschätzbar noch vorstellbar sind.
Ein weiteres Element, das zu Beginn des Jahrhunderts (etwa ab 2015 bis 2020) öffentliche Wahrnehmung erlangt, ist die Künstliche Intelligenz. Sie wird in mehr Software und Hardware eingebunden, und dient etwa zur Ermittlung von effizientieren Abläufen oder Übernahme bestimmter Aufgaben wie Erkennung von Objekten und Lebewesen oder zur Generierung von Bildern. Spätestens mit ChatGPT ab 2022 ist KI bzw. ML (Maschinelles Lernen) in aller Munde und lässt grundlegende Fragen (etwa der Ethik oder des Recht) erneut stellen.
Ab etwa den 2010ern beginnen Tech-Konzerne, den Fokus auf freie und Open-Source-Software zu setzen. Hierbei erstellen sie etliche quelloffnenen Programme, und nutzen selbst diese in ihren Produkten. Zu Beginn der Open-Source-Bewegung gab es seitens der Unternehmen große Vorbehalte bis Ablehnung, was sich jedoch änderte. So wurde das zu Beginn skeptische Microsoft einer der Organisationen mit den meisten FOSS-Beiträgen. Weitere Unternehmen wie Google oder IBM tragen auch regelmäßig bei.
Mit dem Aufkommen von Online-Diensten wie die sozialen Hetzwerke wie Twitter oder Facebook, kommt auf eine "Enshittification" auf. Die Dienste verloren über Zeit an Qualität, und werden teils schlechter moderiert.
In der ersten Hälfte der 2020er, zum KI-Boom, werden vermehrt sogenannte "NPUs" (Neural Proessing Units) verbaut, die KI-basierte Berechnungen beschleunigt durchführen können.
Größer ist ab den 2000ern auch das Bewusstsein für die Bewahrung von (historischen) Computerspielen und Software allgemein geworden. Durch technische Maßnahmen wie Kopierschutz und rechtliche Hürden wie der extrem lange Urheberrechtsschutz wird das erschwert. Da dies kommerziell wenig Ertrag bringt, sind Unternehmen und Konzerne an der Archivierung oder eine freie öffentliche Bereitstellung nicht interessiert. Kritik an der Praxis wird auch laut, dass Spiele immer öfter nicht gekauft, sondern nur zeitlich begrenzte Lizenzen erworben werden (können). So kann ein Spielehersteller Server abschalten, die für das Spielen eines Spiels Voraussetzung sind. Man bleibt auf den Kosten sitzen, und hat nichts mehr davon. Die Kritik an den Urheberrechtspraktiken und die Gier der Konzerne wird öfter lauter. Zur Lösung wird gefordert, den Urheberrechtsschutz an die ursprüngliche Schutzdauer zu binden (ca. 14–20 Jahre nach Veröffentlichung/Erstellung), oder der Patentschutzdauer anzugleichen. Die Lobbyierung Disneys zur praktischen Schutzdauern jenseits der 90 Jahre wird als realitätsfern gesehen. Alternativ wird gefordert, dass es die rechtlich legalisiert wird, geistige Werke (öffentlich) archivieren zu dürfen, oder gar generell nicht-kommerzielle Nutzungen per se zu gestatten. Gemeinnützige Organisationen und Bibliotheken sehen sich aufgrund der gemeinwohlfeindlichen Rechtslage deshalb öfters gerichtlichen Prozessen ausgesetzt, wenn sie urheberrechtlich geschützte Werke digital besitzen und der Allgemeinheit zur Verfügung stellen.
Generell sind archivalische Strukturen und langfristiges Denken in Bezug auf Bewahrung digitaler Werke oft nicht durchdacht bzw. werden nicht standardmäßig in Arbeitsprozesse eingepflegt. So versäumen es Stadtarchive oft, um Fotospenden von Motiven der Stadt etc. zu bitten. Darüber hinaus ist es ein Problem, wenn digitale Güter mit Relevanz für die Gesellschaft in privatwirtschaftlicher Hand sind, wie Kartenmaterial oder Street View-Anwendungen.
Gerade in den 2010ern und 2020ern wandern Institutionen zu Cloudanbietern wie AWS oder OneDrive, auch um "offene Daten" anzubieten. Dies gibt jedoch Probleme in der Datensouveränität und im "Vendor Lock-In". Weder kann sichergestellt werden, dass Datenschutz besteht, noch, dass die Daten dauerhaft zur Verfügung stehen. Auch europäische (Non-Profit-)Organisationen wechseln zu US-amerikanischen Anbietern und machen sich abhängig.
===2001===
* 15.01.2001: Die freie Enzyklopädie {{w|Wikipedia}} geht ans Netz. Sie basiert auf dem Wiki-Prinzip und nutzt die MediaWiki-Software. Besonders ist die Menge an Artikeln, die relativ viele Themen abdecken. Die Seiten der Wikipedia sind einige der meistaufgerufenen Webseiten im WWW.
* 01.02.2001: Der VideoLAN Client wird veröffentlicht. Später nennt man ihn VLC media player. Das freie OpenSource-Programm ist ein Mediaplayer für etliche Multimediadateien und erfreut sich großer Beliebtheit.
* 25.10.2001: Das Kult-Betriebssystem Windows XP erscheint. Besonders populär ist die ''grüne Idylle'' (Bliss) - der Desktophintergrund. Es ist möglicherweise das meistgesehene (oder eines der meistgesehenen Bilder) Bild der Welt.
* Mit der Maxtor DiamondMax 536DX kündigt Maxtor eine der ersten 100-Gigabyte-Festplatten für den Markt an. Sie erreicht 5400 Umdrehungen pro Minute, hat einen 2 MiB großen Cache, 33 GB pro Platter. Die Tranferrate beträgt maximal 30 Megabyte pro Sekunde. Die Schnittstellen sind IDE bzw. Ultra-ATA/100.<ref>https://www.tecchannel.de/a/test-ultra-ata-festplatten,401830,10</ref><ref>https://web.archive.org/web/20010625111550/https://www.maxtor.com/press/2001/nr061801.htm</ref>
<gallery>
Wikipedia-logo-v2.svg|Der unvollständige Puzzle-Ball: Das Wikipedia-Logo
Wikimedia Foundation Servers 2015-90.jpg|Ein Bild des Servers von Wikimedia
VLC Icon.svg|Das Pylonenlogo des VLC media players
VLC media player 3.0.16 screenshot.png|Der VLC media player in der Anwendung
Unofficial fan made Windows XP logo variant.svg|Inoffizielles Flat-Logo von Windows XP
Windows XP wordmark.svg|Offizielles Logo
Bliss hill July 2017.jpg|Leider nicht mehr so schön wie damals: Der Bliss in 2017
Samsung N130 Netbook running Windows XP, 11 December 2019.jpg|Laptop mit Windows XP
EquipoConXP.JPG|Ein Arbeitsplatz mit Windows XP
Payphone loading Microsoft Windows XP.jpg|Teils bis nach Supportende: Windows XP als Embedded-OS eingebettet in Maschinen, die nicht PCs sind
Pleather Factory Computers (33098202786).jpg|Es mag überraschen: Selbst in Nordkorea war bzw. ist Windows XP im Einsatz (neben Red Star OS)
Maxtor DiamondMax Plus 9 80GB-9700.jpg|Ähnliches Maxtor-Modell mit 80 GB
</gallery>
===2002===
* 03.05.2002: Der {{w|Nintendo GameCube}} erscheint.
* 20.09.2002: Tor (The Onion Router) wird eingeführt. Mit dieser Software (u.a. dem Tor Browser) ist es möglich, anonymer zu surfen und Onion-Seiten aufzurufen, die zum {{w|Darknet}} gehören. Im Darknet werden bspw. illegale Drogen verkauft, es erlaubt aber auch anonymes Kommunizieren von Personen des Journalismus in totalitär oder autoriär regierten Ländern.
* 23.09.2002: Der freie Webbrowser {{w|Mozilla Firefox}} erscheint.
{| class="wikitable"
|+ Spezifikationen GameCube
|-
! Typ !! Wert
|-
| Release (Europa)|| 03.05.2002
|-
| CPU || IBM PowerPC 750CXE "Gekko" @ 485 MHz, 1,9 GFLOPS (13 GLOPS System)
|-
| RAM || 24 MiB @ 324 MHz
|-
| GPU || ATI/Nintendo Flipper @ 162 MHz, 0,18 µm (Lithografie), 9,4 GFLOPS, 720 x 480i 50-60 Hz
|-
| Datenträger || MiniDVDs (Panasonic) mit jeweils 1,46 GB
|-
| Controller || GameCube-Controller und Wavebird-Controller
|-
| Verkaufte Einheiten || 21,74 Mio. (bis 30.09.2019)
|-
| Audio || 16-Bit-DSP @ 81 MHz von Macronix
|}
<gallery>
Firefox logo and wordmark (horizontal), 2019.svg|Logo von Mozilla Firefox
Firefox100DarkThemeWin11.png|Screenshot vom Firefox
Tor-logo-2011-flat.svg|Logo von Tor
GameCube-Console-Set.png|GameCube mit Controller
Nintendo-GameCube-Console-BR.jpg|Würfel (hinten)
Gamecube-disk.jpg|Datenträger des GameCube
</gallery>
===2003===
* 24.04.2003: Windows Server 2003 erscheint.
* 12.09.2003: Die digitale Distributionsplattform Steam erscheint für Microsoft Windows. Über Steam lassen sich verschiedene Computerspiele beziehen. 2019 hat die Plattform über eine Milliarde Nutzerkonten.
<gallery>
Steam 2016 logo black.svg|Logo von Steam
</gallery>
===2004===
* 04.02.2004: Das "soziale Netzwerk" facebook geht online. Ähnliche wie andere "soziale Netzwerke" sehen Kritiker dieses Netzwerk als wichtiger Faktor bei der Verbreitung von Fake News und Hassinhalten.
* 07.2004: Das Projekt "OpenStreetMap" erscheint. Es ist ein freies Pendant zu Google Maps und erlaubt eine (bedingte) Weiternutzung der Daten und des Kartenmaterials.
* 20.10.2004: Die erste Version von Ubuntu erscheint. Es ist bis heute (2022) eine der beliebtesten GNU/Linux-Distributionen und stammt von Debian ab. Die erste Version war 4.10 und hieß ''Warty Warthog''.
* 03.12.2004: Prince of Persia: Warrior Within erscheint in der EU. Auch nach knapp 20 Jahren wird das Spiel noch gerne gespielt. Im Spiel geht es um den Prinzen, der zur Insel der Zeit reist, um den Sand der Zeit nicht entstehen zu lassen, und damit sein Schicksal zu ändern. Hierbei begegnet er Kaileena, mit der der Prinz besonders umgeht.
<gallery>
Facebook Logo (2019).svg|Logo von facebook
Openstreetmap logo.svg|Die digitale Karte unter die Lupe nehmen: Das Logo von OSM
WP-OSM-Gadget-Weltkarte.png|Eine digitale Karte von Europa in OSM
Ubuntu-logo-2022.svg|Logo von Ubuntu (2022)
Ubuntu-desktop-2-410-20080706.png|Screenshot von Ubuntu 4.10
</gallery>
===2005===
* 14.02.2005: Die Videoplattform {{w|YouTube}} wird veröffentlicht. Auf ihr lassen sich viele Petabyte (oder gar Exabyte) an Videos finden.
* 11.03.2005: Der Nintendo DS erscheint in Europa.
* Das sogenannte {{w|Perpendicular Magnetic Recording}} (Senkrechtaufzeichnung; Conventional Magnetic Recording) wird in Festplatten kommerziell genutzt.
{| class="wikitable"
|+ Spezifikationen Nintendo DS
|-
! Typ !! Wert
|-
| Release (Europa)|| 11.03.2005
|-
| CPU || ARM9 (32 Bit @ 67 MHz), Subprozessor: ARM7 (32 Bit @ 33 MHz)
|-
| RAM || 4 MiB, 656 K(i?)B VRAM
|-
| Grafik || 2D: Maximal 128 Sprites, 3D: maximal 120000 Polygone pro Sekunde, 30 Millionen Pixel pro Sekunde Füllrate
|-
| Display || 256 x 192 Pixel, 3", 262144 Farben (2<sup>18</sup>)
|-
| Datenträger || Speichermodule (max. 512 MB oder 512 MiB)
|-
| Verkaufte Einheiten || 154,02 Mio. (DS, DS Lite, DSi (XL))
|-
| Audio || Stereo
|}
<gallery>
YouTube Logo 2017.svg|Logo von YouTube
Me at the zoo.webm|Das erste Video auf YouTube ''Me at the zoo''
Nintendo DS Logo.svg|Logo des Nintendo DS
Nintendo-DS-Fat-Blue.png|Ein Nintendo DS in blau
Nintendo DS Lite logo.svg|Logo des Nintendo DS Lite
DSLite white trans.png|Nintendo DS Lite mit Warnhinweis
Perpendicular Recording.svg|Aufbau des CMR
</gallery>
===2006===
* 04.2006: Der Online-Dienst Google Übersetzer erscheint. Die Übersetzungen wurden über die Zeit besser.
* 08.11.2006: Windows Vista erscheint. Das Betriebssystem wird nicht so erfolgreich wie Windows 7, sieht diesem aber ähnlich. Updates werden ab 11.04.2017 nicht mehr bereitgestellt.
* 08.12.2006: Die Nintendo Wii erscheint auf dem europäischen Markt. Durch die Bewegungssteuerung der Wii-Fernbedienung wurde die Konsole beliebt.
<gallery>
Google Translate logo.svg|Logo des Google Übersetzers
Wii.svg|Logo der Wii
Wii-Console.png|Die Wii in weiß
Microsoft Windows Vista wordmark.svg|Logo von Windows Vista
</gallery>
===2007===
* Mit dem Hitachi CinemaStar 7K1000 kommt eine der ersten 1-TB-Festplatten für den Endverbrauch auf den Markt.<ref>https://www.oe24.at/digital/computer/erste-festplatte-mit-1-tb-speicher/66610</ref>
* 15.01.2007: Die Virtualisierungssoftware {{w|VirtualBox}} erscheint. Ursprünglich von Innotek entwickelt, wird es später von Oracle betreut und weiterentwickelt. Das Programm ist freie Open-Source-Software. Der größte Konkurrent ist wohl VMware Workstation, dessen Nutzung jedoch kostenpflichtig ist.
* 09.11.2007: Das erste {{w|iPhone (1. Generation)}} erscheint. Es ist eines der ersten Smartphones im verbreiteten Sinne.
{| class="wikitable"
|+ Spezifikationen des iPhone
|-
! Typ !! Wert
|-
| Release || 09.11.2007
|-
| Display || 3,5" bei 480 x 320 Pixel
|-
| Kamera 1 || 2 Megapixel
|-
| Betriebssystem zu Beginn || iPhoneOS 1.0
|-
| SoC || Samsung S5L8900
|-
| CPU || Einkerner ARM 1176 @ 412 MHz
|-
| RAM || 128 MiB LPDDR1 @ 137 MHz
|-
| GPU || PowerVR MBX Lite @ 60 MHz
|-
| Storage || 4, 8 oder 16 GB NAND-Flash
|-
| Masse || 135 Gramm
|}
<gallery>
Toshiba HDD 1TB.jpg|Eine andere HDD von Toshiba mit 1 TB
IPhonelogo.svg|Logo des iPhone
IPhone First Generation.jpg|Das iPhone
IPhone 1st Gen.svg|iPhone als Vektorgrafik
Steve Jobs presents iPhone.jpg|Steve Jobs präsentiert das iPhone
</gallery>
===2008===
* 27.02.2008: Windows Server 2008 erscheint. Es sieht Windows Server 2003 ähnlich, hat jedoch neuere Icons. Server 2008 erscheint mit 32- und 64-Bit-Versionen.
* 16.06.2008: Die NVIDIA GeForce GTX 280 erscheint.
* 23.09.2008: Die freie Software Android erscheint für Smartphone. Android wird das verbreiteste Betriebssystem für Smartphones und ist freie Software. Im Q3 2023 hatte Android einen Marktanteil von etwa 70,46 %, iOS 28,83 %.
* Die Intel Core-i-Serie wird eingeführt. Je nach i-Nummer haben sie etwa mehr Kerne oder anderweitig mehr Leistung. i3-CPUs sind eher für den Low-End-Bereich gedacht, i5-CPUs für besser ausgestattete Office-Rechner, i7-CPUs für Gaming und i9-CPUs für Gaming und Rendering.
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce GTX 280<ref>https://www.techpowerup.com/gpu-specs/geforce-gtx-280.c216</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 16.06.2008
|-
| Plattform || GeForce GTX
|-
| Generation || GTX 200
|-
| Architektur || Tesla 2.0
|-
| GPU || GT200
|-
| GPU-Subtyp || G200-300-A2
|-
| Die-Größe || 5,76 cm²
|-
| Cachegröße (L2) || 256 KiB
|-
| Baugröße || 65 Nanometer
|-
| Transistormenge || 1,4 Milliarden
|-
| Slotbreite || 2 Slots
|-
| Abmessungen || 267 mm
|-
| Kerne (Shader)|| 240
|-
| Texture Mapping Units || 80
|-
| Render Output Units || 32
|-
| Streaming Multiprocessors || 30
|-
| Grafikspeicher || 1024 MiB
|-
| Grafikspeichertyp || GDDR3
|-
| Busbreite || 512 bit
|-
| Schnittstelle || PCIe 2.0 (x16)
|-
| Basistakt || 602 MHz (Memory: 1,107 GHz)
|-
| Shadertakt || 1,296 MHz
|-
| Bandbreite Speicher || 141,7 GB/s
|-
| Thermal Design Power || 236 Watt
|-
| Anschlüsse || 2x DVI, 1x S-Video
|-
| CUDA-Version || 1.3
|-
| DirectX-Version || 11.1/10_0
|-
| OpenGL-Version || 3.3
|-
| OpenCL-Version || 1.1
|-
| Shader-Version || 4.0
|-
| Vulkan-Version || -
|-
| Pixelfüllrate || 19,26 Gigapixel/Sekunde
|-
| Texturrate || 48,16 Gigatexel/Sekunde
|-
| FP32-Leistung (float) || 622,1 GigaFLOPS
|-
| FP64-Leistung (double) || 77,76 GigaFLOPS
|-
|}
<gallery>
NVIDIA GeForce GTX280 DSC01106 (23505776839).jpg|Auseinandergebaute GTX 280
Android logo 2019 (stacked).svg|Logo von android
Android 1.0 homescreen.png|Screenshot von android 1.0
Intel Core i3 2020 logo.svg|Logo des Intel-Core-i3 (2020)
Intel Core i5 2020 logo.svg|Logo des Intel-Core-i5 (2020)
Intel Core i7 2020 logo.svg|Logo des Intel-Core-i7 (2020)
Intel Core i9 2020 logo.svg|Logo des Intel-Core-i9 (2020)
</gallery>
===2009===
* 03.01.2009: Mit {{w|Bitcoin}} wird der Markt der Kryptowährungen langsam populär. Sie sind dezentral und nutzen oft Blockchains. und Hashes. Sie stehen in der Kritik, weil sie unter anderem für illegale Geschäfte relativ oft genutzt werden oder durch "schürfen" (Rechner führen aufwendige Rechnungen durch und verbrauchen viel Strom) viel Strom verbrauchen.
* 22.10.2009: Windows 7 erscheint. Im Gegensatz zu Windows Vista wird Windows 7 sehr erfolgreich. Der Support für die Endkundschaft endet am 14.01.2020.
* ImageNet wird vorgestellt. Hierbei handelt es sich um eine Bilderdatenbank, wo jedes Bild einem Substantiv zugeordnet wird. Es soll bei "machine learning" helfen. Am 10. Februar 2024 hatte es knapp 14,2 Millionen Bilder.
<gallery>
Bitcoin logo.svg|Das Logo des Bitcoin
Hut 8 Medicine Hat box 1.jpg|Hier werden viele Bitcoins geschürft: in sogenannten Rechenfarmen
Unofficial fan made Windows 7 logo variant.svg|Flat-Logo von Windows 7
Windows7beta.jpg|Vorabversion von Windows 7 auf einer DVD
</gallery>
===2010===
* 28.09.2010: Die freie Officesuite LibreOffice erscheint. Sie enthält Software für Textverarbeitung, Tabellenkalkulation, Präsentation, Zeichnung, Formelbearbeitung und zur Verealtung von Datenbanken. Das Softwarepaket gibt es für mehrere Betriebssysteme wie GNU/Linux, MS Windows, macOS oder Android.
* 06.10.2010: Das später zu Meta Platforms gehörende "soziale Netzwerk" Instagram wird gelauncht. Es fokussiert sich auf das Posten von Fotos. Die Abmessungen der Fotos betragen 1080 Pixel in der kürzeren Dimension, und meist 100-400 Kilobyte pro Bild. Mit Filtern und anderen Tools werden die Bilder häufig manipuliert. Bis Oktober 2015 wurden etwa über 40 Milliarden Fotos hochgeladen. Kritisiert wird die Plattform wegen der teils negativen Auswirkungen, vor allem auf Kinder und Jugendliche, etwa durch manipulierte Fotos, die etwas anderes vorgaukeln (aufgehübschte Bilder, das Präsentieren von Stars nur von der positivsten Seite, etc.), als die Realität.
<gallery>
LibreOffice Logo Flat.svg|Logo von LibreOffice
LibreOffice 6.4.1.2 2020.06.23 - 14.50.29.29.png|Willkommenbildschirm von LibreOffice
Instagram Filters 2011.jpg|Filter unter Instagram
</gallery>
===2011===
* 16.02.2011: Die künstliche Intelligenz '''Watson''' von IBM gewinnt in der Quizshow ''Jeopardy'' gegen Experten der Sendung.
* 25.03.2011: Der Nintendo 3DS erscheint in Europa. Er ist der Nachfolger des Nintendo DSi und kann stereoskopische Effekte wiedergeben. Trotz anfänglicher schlechter Verkaufszahlen verkaufte sich der Handheld später besser. Spezifikationen: CPU: ARM1 Zweikerner @ 268 MHz, 128 MiB RAM, GPU: Pica200 (6 MiB VRAM). Bis September 2020 wurden knapp 76 Millionen Einheiten verkauft.
<gallery>
Nintendo 3DS logo.svg|Logo des Nintendo 3DS
Nintendo-3DS-AquaOpen.png|Blauer Nintendo 3DS
</gallery>
===2012===
* 26.10.2012: Windows 8 erscheint. Neu ist die Kacheloptik, die jedoch auf wenig Gegenliebe trifft. Mit Windows 8.1 erscheint ein Update mit dem altbekannten Desktop.
* 30.11.2012: Die Nintendo Wii U erscheint im europäischen Markt. Die Wii U ist der Nachfolger der Nintendo Wii. Bis Ende Juni 2020 wurden etwa 13,56 Mio. Einheiten verkauft, knapp 100 Mio. weniger als die Nintendo Switch. Spezifikationen: CPU: IBM Espresso @ 1,24 GHz, GPU: AMD Latte @ 550 MHz
* Der kleine Einplatinenrechner Raspberry Pi erscheint in seiner Ursprungsfassung.
<gallery>
Windows 8 logo and wordmark.svg|Das Logo von Windows 8
LibreOffice 4.3 Windows 8.1.PNG|LibreOffice unter Windows 8.1
WiiU.svg|Logo der Wii U
Nintendo-Wii-U-Console-FL.jpg|Die Konsole Wii U
Wii U Gamepad schwarz.JPG|Das Wii-U-Gamepad
Raspberry Pi 4 Model B - Side.jpg|Ein Raspberry-Pi-Computer
</gallery>
===2013===
* 30.04.2013: IBM Research bringt einen Kurzfilm heraus, der im Stile einer Stop-Motion-Produktion erstellt wurde. Er zeigt einen Jungen, der mit seinem Atom spielt. Die im Film zu sehenden Strukturen sind kaum größer als einzelne Atome.
* 23.05.2013: Die NVIDIA GeForce GTX 780 erscheint.
* 22.11.2013: Die XBOX One erscheint auf dem europäischen Markt. Bis 11.2020 wurden etwa 48,47 Millionen Einheiten verkauft. Spezifikationen: CPU: AMD Jaguar x86 (Achtkerner), GPU: Graphics Core Next. Mehr, siehe: [[w:Xbox One|Xbox One]]
* 29.11.2013: Die PlayStation 4 kommt auf dem europäischen Markt. Bis Ende März 2022 wurden 117 Millionen Einheiten verkauft. Spezifikationen: CPU: AMD Jaguar x86 (1,6 GHz), GPU: AMD-Radeon-GPU (Graphics Core Next). Mehr, siehe: [[w:PlayStation_4|PlayStation_4]]
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce GTX 780<ref>https://www.techpowerup.com/gpu-specs/geforce-gtx-780.c1701</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 23.05.2013
|-
| Plattform || GeForce GTX
|-
| Generation || GTX 700
|-
| Architektur || Kepler
|-
| GPU || GK110
|-
| GPU-Subtyp || GK110-300-A1
|-
| Die-Größe || 5,61 cm²
|-
| Cachegröße (L1) || 16 KiB pro SMX
|-
| Cachegröße (L2) || 1536 KiB
|-
| Baugröße || 28 Nanometer
|-
| Transistormenge || 7,08 Milliarden
|-
| Slotbreite || 2 Slots
|-
| Abmessungen || 267 mm x 111 mm x 38 mm
|-
| Kerne (Shader)|| 2304
|-
| Texture Mapping Units || 192
|-
| Render Output Units || 48
|-
| SMX || 12
|-
| Grafikspeicher || 3072 MiB
|-
| Grafikspeichertyp || GDDR5
|-
| Busbreite || 384 bit
|-
| Schnittstelle || PCIe 3.0 (x16)
|-
| Basistakt || 0,863 GHz (Memory: 1,502 GHz)
|-
| Boosttakt || 0,902 MHz
|-
| Bandbreite Speicher || 288,4 GB/s
|-
| Thermal Design Power || 250 Watt
|-
| Anschlüsse || 1x DisplayPort 1.2, 1x HDMI 1.4a, 2x Digital Visual Interface
|-
| CUDA-Version || 3.5
|-
| DirectX-Version || 12/11_0
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 5.1
|-
| Vulkan-Version || 1.1
|-
| Pixelfüllrate || 43,30 Gigapixel/Sekunde
|-
| Texturrate || 173,2 Gigatexel/Sekunde
|-
| FP32-Leistung (float) || 4,156 TeraFLOPS
|-
| FP64-Leistung (double) || 173,2 GigaFLOPS
|}
<gallery>
A Boy and His Atom Movie Stills (8675821573).jpg|Wohl das kleinste Video der Welt: Atome als Schauspieler
NVIDIA GeForce GTX 780 PCB-Front.jpg|Die GeForce GTX 780 ohne Kühlkörper
X Box One logo.svg|Wortmarke der Xbox One
Microsoft-Xbox-One-Console-Set-wKinect.jpg|Xbox One in schwarz
PlayStation 4 logo and wordmark.svg|Die Wortmake der PS4
Sony-PlayStation-4-PS4-wDualShock-4.jpg|PS4-Konsole mit Kontroller
</gallery>
===2014===
* 05.2014: Das erste bekannte NFT ({{w|Non-Fungible Token}}) wird erschaffen. NFTs sollen mit einer Blockchain ein krytografisches individuelles Token enthalten, das eine Einzigartigkeit eines Gegenstandes darstellt. Die Kritiken und Probleme decken sich teils mit denen von Kryptowährungen wie Bitcoin.
* 30.05.2014: Der Funracer Mario Kart 8 erscheint für die Wii U auf dem europäischen Markt. Das Spiel hat Freundschaften kommen und vor allem gehen sehen, erfreut sich aber dennoch großer Beliebtheit. Neu ist unter anderem das Fahren mit Antigravitation. Später kommen neue Fahrer wie Link und neue Strecken hinzu.
* 19.09.2014: Die NVIDIA GeForce GTX 980 erscheint.
* 26.08.2014: Seagate verbreitet die erste 8-TB-Festplatte.<ref>https://www.seagate.com/de/de/news/news-archive/Seagate-ships-worlds-first-8TB-hard-drives-pr-master/</ref>
* Der DDR4-SDRAM-Standard wird in Form von RAM-Riegeln auf den Markt gebracht
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce GTX 980<ref>https://www.techpowerup.com/gpu-specs/geforce-gtx-980.c2621</ref><ref>https://www.nvidia.com/de-de/geforce/900-series/#specsmodal-980</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 19.09.2014
|-
| Plattform || GeForce GTX
|-
| Generation || GTX 900
|-
| Architektur || Maxwell 2.0
|-
| GPU || GM204
|-
| GPU-Subtyp || GM204-400-A1
|-
| Die-Größe || 3,98 cm²
|-
| Cachegröße (L1) || 48 KiB pro Streaming Multiprocessor
|-
| Cachegröße (L2) || 2 MiB
|-
| Baugröße || 28 Nanometer
|-
| Transistormenge || 5,2 Milliarden
|-
| Slotbreite || 2 Slots
|-
| Abmessungen || 267 mm x 111 mm x 40 mm
|-
| Kerne (Shader)|| 2048
|-
| Texture Mapping Units || 128
|-
| Render Output Units || 64
|-
| Streaming Multiprocessors || 16
|-
| Grafikspeicher || 4096 MiB
|-
| Grafikspeichertyp || GDDR5
|-
| Busbreite || 256 bit
|-
| Schnittstelle || PCIe 3.0 (x16)
|-
| Basistakt || 1,127 GHz (Memory: 1,753 GHz)
|-
| Boosttakt || 1,216 MHz
|-
| Bandbreite Speicher || 224,4 GB/s
|-
| Thermal Design Power || 165 Watt
|-
| Anschlüsse || 3x DisplayPort 1.4a, 1x HDMI 2.0, 1x Digital Visual Interface
|-
| CUDA-Version || 5.2
|-
| DirectX-Version || 12/12_1
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 6.4
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 77,82 Gigapixel/Sekunde
|-
| Texturrate || 155,6 Gigatexel/Sekunde
|-
| FP32-Leistung (float) || 4,981 TeraFLOPS
|-
| FP64-Leistung (double) || 155,6 GigaFLOPS
|-
| Maximal zulässige Temperatur || 98 °C
|}
<gallery>
Mario Kart logo.png|Logo von Mario Kart
Link at Igromir 2012.jpg|Neben Held auch Profifahrer (zumindest in Mario Kart 8)
DDR4 Ram IMGP5859 smial wp.jpg|Ein DDR4-RAM-Riegel mit Kühlkörper
16 GiB-DDR4-RAM-Riegel RAM019FIX Small Crop 90 PCNT.png|Ein RAM-Stick (DDR4)
</gallery>
===2015===
* 29.07.2015: Windows 10 erscheint
* Sommer 2015: Google macht {{w|DeepDream}} öffentlich. Mit ihr lassen sich dank neuronaler Netze Texturen auf Bilder legen, die dann nur scheinbar das ursprüngliche Bild zeigen, tatsächlich sind es aber kleinere detaillierte Strukturen wie Tierstrukturen.
* 10.2015: Das Computerprogramm {{w|AlphaGo}} schlägt den Europameister Fan Hui im Brettspiel Go.
{| class="wikitable"
|+ Systemvoraussetzungen für Windows 10 (jeweils 64-Bit)
|-
! Aspekt !! Wert
|-
| CPU || CPU 1 GHz mit PAE, NX und SSE2, CMPXCHG16b, PrefetchW, LAHF/SAHF
|-
| RAM || 2 GiB
|-
| Grafik || DirectX 9+ mit WDDM-1.0-Treiber, 800x600 Pixel
|-
| HDD || 20 Gigabyte (bis Version 1809 (18H2)), 32 Gigabyte ab Version 1903 (19H1))
|}
<gallery>
DeepDream SchillerGym 20210821 Hof04021 RAW 202109251094CROP.jpg|Der Computer "träumt": Ist das Ergebnis eine Schule? Oder eine Häufung von tierähnlichen Strukturen? Oder beides? Oder gar nichts?
Windows 10 Logo.svg|Windows 10 - Das Logo ähnelt Windows 8
AlphaGo.svg|Logo von AlphaGo
</gallery>
===2016===
* 27.05.2016: Die NVIDIA GTX 1080 erscheint.
* 06.07.2016: Das Augmented-Reality-Spiel für das Smartphone '''Pokémon Go''' erscheint. Mit ihm kann man draußen Pokémon fangen.
* 09.2016: Das "soziale Netzwerk" TikTok geht online. Es bietet kurze Videoclips, die von Usern erstellt und geteilt werden können. Kritiker kritisieren den (möglichen) Einfluss der chinesischen Regierung und die Manipulation von vor allem jungen Usern.
* 05.10.2016: Das dezentrale und freie Microblogging-Netzwerk {{w|Mastodon (Software)}} wird gelauncht. Das Netzwerk ist nicht profitorientiert und vom Grundaufbau her ähnlich zu Twitter, jedoch auf mehrere Server verteilt.
* Der Internetverkehr steigt auf über ein Zettabyte an.<ref>https://www.telegraph.co.uk/technology/2016/02/04/worlds-internet-traffic-to-surpass-one-zettabyte-in-2016/</ref>
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce GTX 1080<ref>https://www.techpowerup.com/gpu-specs/geforce-gtx-1080.c2839</ref><ref>https://www.nvidia.com/de-de/geforce/10-series/</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 27.05.2016
|-
| Plattform || GeForce GTX
|-
| Generation || GTX 10
|-
| Architektur || Pascal
|-
| GPU || GP104
|-
| GPU-Subtyp || GP104-400-A1
|-
| Die-Größe || 3,14 cm²
|-
| Cachegröße (L1) || 48 KiB pro Streaming Multiprocessor
|-
| Cachegröße (L2) || 2 MiB
|-
| Baugröße || 16 Nanometer
|-
| Transistormenge || 7,2 Milliarden
|-
| Slotbreite || 2 Slots
|-
| Abmessungen || 267 mm x 112 mm x 40 mm
|-
| Kerne (Shader)|| 2560
|-
| Texture Mapping Units || 160
|-
| Tensor-Kerne || (368)
|-
| Render Output Units || 64
|-
| Streaming Multiprocessors || 20
|-
| Grafikspeicher || 8192 MiB
|-
| Grafikspeichertyp || GDDR5X
|-
| Busbreite || 256 bit
|-
| Schnittstelle || PCIe 3.0 (x16)
|-
| Basistakt || 1,607 GHz (Memory: 1,251 GHz)
|-
| Boosttakt || 1,733 MHz
|-
| Bandbreite Speicher || 320,3 GB/s
|-
| Thermal Design Power || 180 Watt
|-
| Anschlüsse || 3x DisplayPort 1.4a, 1x HDMI 2.0, 1x Digital Visual Interface
|-
| CUDA-Version || 6.1
|-
| DirectX-Version || 12/12_1
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 6.4
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 110,9 Gigapixel/Sekunde
|-
| Texturrate || 277,3 Gigatexel/Sekunde
|-
| FP16-Leistung (half) || 138,6 GigaFLOPS
|-
| FP32-Leistung (float) || 2,873 TeraFLOPS
|-
| FP64-Leistung (double) || 277,3 GigaFLOPS
|-
| Generation Tensor-Kerne || ???
|-
| NVIDIA Encoder || ???
|-
| NVIDIA Decoder || ???
|-
| Maximal unterstützte Auflösung || 7680 x 4320 Pixel (@ 60 Hz, 8 Bit RGB mit 2xDP 1.4a // @ 60 Hz, YUV420 8-bit bei einem DisplayPort 1.3-Anschluss)
|-
| Maximal unterstützte Bildschirme || mind. 2
|-
| Maximal zulässige Temperatur || 94 °C
|}
<gallery>
NVIDIA-GTX-1070-FoundersEdition-FL.jpg|Die NVIDIA GTX 1070
App-augmented-reality-game-gps-163042.jpg|Gehen und aufs Handy gucken - die Kombination kann gefährlich sein
TikTok and YouTube Shorts example.webm|Beispiel eines Videoclips für TikTok
Mastodon logotype (simple) new hue.svg|Logo von Mastodon mit einem Schema eines Elefanten
</gallery>
===2017===
* Das WannaCry-Virus (Ransomware) verbreitet sich. Wie bei Ransomware üblich, wird der Inhalt eines infizierten Rechners verschlüsselt und (angeblich) nur gegen Geld wieder entschlüsselt. Als Ursprung vermutet man Nordkorea.
* 03.03.2017: Nintendo veröffentlicht seine Hybrid-Konsole '''Nintendo Switch'''. Die Tatsachen, dass die Konsole mobil ist und es gute Spiele gibt, machten die Konsole beliebt und liefert über 100 Millionen verkaufte Einheiten.
* 03.03.2017: Das von vielen erwartete und deutlich verspätete '''The Legend of Zelda: Breath of the Wild''' erscheint. Es ist das erste echte Open-World-Zelda-Spiel und kommt mit einem frei bekleidbaren Link daher, der Sidon als seinen Freund gewinnt und sich in Crossdressing versucht.
* 20.06.2017: AMD launcht seine EPYC-Mikroprozessoren. Diese sollen eine Konkurrenz zu Intel Xeon-Mikroprozessoren sein. Trotz dessen, dass Server-CPUs bei Release ziemlich teuer sind, so kann man online auch günstige Produkte (gebraucht) erwischen.
* 27.06.2017: Die Schadsoftware ''NotPetya'' verbreitet sich und kompromittiert verschiedene Rechner auf der ganzen Welt. Der Schaden wird auf 300 Mio. US-$ beziffert.
* 11.2017: Alle Supercomputer aus dem TOP500 laufen auf einem Betriebssystem, basierend auf dem Linux-Kernel. Linux hat über die Zeit Unix verdrängt. OS-Architekturen wie die von BSD, Windows und Mac blieben enorm erfolglos.
<gallery>
Countries initially affected in WannaCry ransomware attack.svg|Ausbreitung des WannaCry-Virus
Nintendo-Switch-Console-Docked-wJoyConRB.jpg|Die Controller sind abkoppelbar. Das "Herzstück" lässt sich aus der Docking-Station entnehmen
The Legend of Zelda Breath of the Wild.svg|BotW ist beliebt. Wo geht die Reise hin?
Amd epyc 7302 socket sp3 IMGP3493 smial wp.jpg|Server-CPUs wie diese sind deutlich größer als Desktop-CPUs
Operating systems used on top 500 supercomputers.svg|Historisch waren Unix und Linux beliebt. Der Rest hat keine Chance.
</gallery>
===2018===
* 03.2018: Der sogenannte Nintendo Gigaleak (bzw. Nintendo data leak) kommt ins Rollen. Über die folgenden Jahre wurden Daten wie Quellcode, aber auch persönliche Daten aus dem Konzern bezogen und teilweise veröffentlicht. Das Ereignis offenbart ein Dilemma: nur durch den Quellcode alter Software können die Spiele für die Nachwelt dezentral gesichert werden, gerade, wenn Nintendo in Insolvenz geht, sich auflöst bzw. die Daten löscht oder verliert. Nintendo geht sehr hart gegen Verletzungen seines geistigen Eigentums vor, aber auch das Unternehmen kann nicht alles verbergen, was es gerne verborgen hätte. Die gesamte kompromittierte Datenmenge könnte über 2 TB liegen.
* 06.2018: Die Kategorie "SDUC" (Secure Digital Ultra Capacity) wird vorgestellt. Unter diese Kategorie fallen (Micro)SD-Karten von über 2 bis 128 Terabyte. Bis es allerdings 128-Terabyte-SDUC-Karten gibt, wird es wohl bis in die 2030er dauern.
* 08.2018: AMD bringt den AMD Ryzen Threadripper 2990WX auf den Markt. Der Prozessor ist einer der ersten Desktop-CPUs, der 32 Kerne enthält.
* 20.09.2018: Die NVIDIA-GeForce-RTX-20er-Reihe erscheint. Die reine Rechenleistung nahm nur relativ wenig zu, jedoch wurden Raytracing-Kerne hinzugefügt, die in Echtzeit Raytracing berechnen sollen. Ob diese Funktionen sich durchsetzen, war zum Zeitpunkt des Releases noch nicht sicher.<ref>https://www.nvidia.com/de-de/geforce/20-series/</ref>
* Samsung veröffentlicht einen der ersten 8K-Fernseher (7680×4320 Pixel; QLED TV Q900) für den Endverbraucher/die Endverbraucherin. Der Fernseher ist in den Diagonalen 65", 75" und 85" erhältlich. Zusätzliche Funktionen sind ein Quantum Prozessor 8K mit künstlicher Intelligenz und High-Dynamic Range. Ein großes Problem bleiben jedoch die spärlichen Inhalte mit 8K.
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce RTX 2080<ref>https://www.techpowerup.com/gpu-specs/geforce-rtx-2080.c3224</ref><ref>https://www.nvidia.com/de-de/geforce/graphics-cards/compare/?section=compare-20</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 20.09.2018
|-
| Plattform || GeForce RTX
|-
| Generation || RTX 20(00)
|-
| Architektur || Turing
|-
| GPU || TU104
|-
| GPU-Subtyp || TU104-400A-A1
|-
| Die-Größe || 5,45 cm²
|-
| Cachegröße (L1) || 64 KiB pro Streaming Multiprocessor
|-
| Cachegröße (L2) || 4 MiB
|-
| Baugröße || 12 Nanometer
|-
| Transistormenge || 13,6 Milliarden
|-
| Slotbreite || 2 Slots
|-
| Abmessungen || 267 mm x 116 mm x 35 mm
|-
| Kerne (Shader)|| 2944
|-
| Texture Mapping Units || 184
|-
| Tensor-Kerne || 368
|-
| Render Output Units || 64
|-
| Streaming Multiprocessors || 46 (entspricht Anzahl Raytracing-Kerne)
|-
| Grafikspeicher || 8192 MiB
|-
| Grafikspeichertyp || GDDR6
|-
| Busbreite || 256 bit
|-
| Schnittstelle || PCIe 4.0 (x16)
|-
| Basistakt || 1,515 GHz (Memory: 1,75 GHz)
|-
| Boosttakt || 1,710 MHz
|-
| Bandbreite Speicher || 448 GB/s
|-
| Thermal Design Power || 215 Watt
|-
| Anschlüsse || 3x DisplayPort 1.4a; 1x HDMI 2.0, 1x USB Typ C
|-
| CUDA-Version || 7.5
|-
| DirectX-Version || 12 Ultimate/12_2
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 6.6
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 109,4 Gigapixel/Sekunde
|-
| Texturrate || 314,6 Gigatexel/Sekunde
|-
| FP16-Leistung (half) || 20,14 TeraFLOPS
|-
| FP32-Leistung (float) || 10,07 TeraFLOPS
|-
| FP64-Leistung (double) || 314,6 GigaFLOPS
|-
| Generation Raytracing-Kerne || 1. Generation
|-
| Generation Tensor-Kerne || 2. Generation
|-
| Deep Learning Super Sampling || Ja
|-
| NVIDIA Encoder || 7. Generation
|-
| NVIDIA Decoder || 4. Generation
|-
| Maximal unterstützte Auflösung || 7680 x 4320 Pixel (@ 60 Hz, 12-Bit-HDR mit DP 1.4a und DSC/HDMI 2.1 + DSC // @ 120 Hz bei zweifachem DP 1.4a und DSC), 3840 x 2160 Pixel (@ 240 Hz, 12-Bit-HDR mit DP 1.4a und DSC)
|-
| Maximal unterstützte Bildschirme || 4
|-
| Maximal zulässige Temperatur || 89 °C
|}
<gallery>
SDUC.svg|Das Logo des SDUC-Standards
GeForce RTX 20 Series logo with slogan.svg|Slogan der RTX-20er-Reihe
Größenvergleich GeForce RTX 2080 und GeForce RTX 3090 DSC6318.jpg|Die RTX 2080 war noch deutlich kleiner als die üppige RTX 3090
</gallery>
===2019===
* 09.04.2019: Der erweiterte Support für Windows Embedded POS 2009 endet, und damit der letzte (öffentliche) Support für die Windows-XP-Codebasis.
* 07.2019: Wissenschaftler gelingt es, den Text der englischen Wikipedia auf synthetischer DNA zu speichern (16 GB).
* 05.09.2019: Die erste Version der PowerToys für Windows 10 erscheint. Die PowerToys gehen bis auf Windows 95 zurück, und bieten aktuell nützliche Programme wie den ColorPicker, den PowerRename für die Umbenennung vieler Dateien oder PowerOCR (ab 2022), der Text aus Bildern extrahiert. Das Projekt steht unter der MIT-Lizenz.
* 23.10.2019: Google-Forscher behaupten, eine Quantenüberlegenheit durchgeführt zu haben. Hintergrund war eine Rechenaufgabe, die ein Quantencomputer sehr viel schneller als ein Binärrechner löste.
* Micron und SanDisk zeigen eine der ersten 1-TB-microSDXC-Karten.
<gallery>
2020 PowerToys Icon.svg|Automatisierung und nützliche Werkzeuge: PowerToys kombiniert beides
Google Sycamore Chip 002.png|Er war zuständig für das Berechnen: Der Quantenprozessor Sycamore
</gallery>
===2020===
* Aufgrund des Einhaltens von Abständen werden Videokonferenzen und Home Office während der COVID-19-Pandemie populär. Nach der Pandemie steigt das Angebot von Home Office (remote working) stark an.
* 13.03.2020: Mit dem Samsung Galaxy S20 erscheint eines der ersten Smartphones, die eine 8K-FUHD-Videoaufnahme ermöglichen (aufgrund der kleinen Größe des Bildsensors ist eine volle Ausreizung der Detailtiefe, die mit 8K möglich wäre, nicht zu erwarten)<ref>https://www.samsung.com/de/smartphones/galaxy-s20/</ref>
* Q2 2020: Die 10. Generation der Intel-Core-Serie erscheint.
* 08.2020: Das Gadget '''Flipper Zero''' erscheint. Das kleine Gerät mit LCD wurde vor allem durch seine "Hackfähigkeiten" bekannt und wird kontrovers diskutiert.
* 09.2020: Mit der GeForce RTX 3090 veröffentlicht NVIDIA die (von NVIDIA ernannte) erste 8K-Grafikkarte. Inwieweit 8K nutzbar ist, hängt vom Spiel ab. Einige Spiele schafft die Karte mit mittleren bis hohen Grafikeinstellungen in 8K und 30-60 FPS, mit DLSS meist mehr.<ref>https://www.nvidia.com/de-de/geforce/graphics-cards/30-series/rtx-3090-3090ti/</ref>
* Mit der Samsung 870 QVO bringt Samsung eine der ersten 8-TB-SSDs auf den Markt (für Endkundschaft). Die enthaltenen QLCs erlauben eine höhere Speicherdichte, sind jedoch zumindest im längeren ununterbrochenen Betrieb langsamerwerdend.<ref>https://tigernation.de/2020/06/30/erste-8tb-ssd-von-samsung/</ref>
* 05.11.2020: Die ersten Modelle des AMD Ryzen 5000 (Vermeer) erscheinen. Die Modelle haben 6 bis 16 Prozessorkerne.
{| class="wikitable"
|+ Spezifikationen Gigabyte RTX 3090 Eagle OC<ref>https://www.techpowerup.com/gpu-specs/gigabyte-rtx-3090-eagle-oc.b7951</ref>
|-
! Typ !! Wert
|-
| Codename || GV-N3090EAGLE OC-24GD
|-
| Hersteller || Gigabyte
|-
| Erscheinungsdatum || 24.09.2020
|-
| Plattform || GeForce RTX
|-
| Generation || RTX 30(00)
|-
| Architektur || Ampere
|-
| GPU || GA102
|-
| GPU-Subtyp || GA102-300-A1
|-
| Die-Größe || 6,28 cm²
|-
| Cachegröße (L1) || 128 KiB pro Streaming Multiprocessor
|-
| Cachegröße (L2) || 6 MiB
|-
| Baugröße || 8 Nanometer
|-
| Transistormenge || 28,3 Milliarden
|-
| Slotbreite || 3 Slots
|-
| Abmessungen || 330 mm x 130 mm
|-
| Kerne (Shader)|| 10496
|-
| Texture Mapping Units || 328 (≙ Tensor-Kerne)
|-
| Render Output Units || 112
|-
| Streaming Multiprocessors || 82 (≙ Raytracing-Kerne)
|-
| Grafikspeicher || 24576 MiB
|-
| Grafikspeichertyp || GDDR6X
|-
| Busbreite || 384 bit
|-
| Schnittstelle || PCIe 4.0 (x16)
|-
| Basistakt || 1,395 GHz
|-
| Boosttakt || 1,725 MHz
|-
| Bandbreite Speicher || 936,2 GB/s
|-
| Thermal Design Power || 350 Watt
|-
| Anschlüsse || 3x DisplayPort 1.4a; 2x HDMI 2.1
|-
| CUDA-Version || 8.6
|-
| DirectX-Version || 12 Ultimate/12_2
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 6.6
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 193,2 Gigapixel/Sekunde
|-
| Texturrate || 565,8 Gigatexel/Sekunde
|-
| FP16-Leistung (half) || 36,21 TeraFLOPS
|-
| FP32-Leistung (float) || 36,21 TeraFLOPS
|-
| FP64-Leistung (double) || 565,8 GigaFLOPS
|}
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce RTX 3090<ref>https://www.techpowerup.com/gpu-specs/geforce-rtx-3090.c3622</ref><ref>https://www.nvidia.com/de-de/geforce/graphics-cards/30-series/rtx-3090-3090ti/</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 24.09.2020
|-
| Plattform || GeForce RTX
|-
| Generation || RTX 30(00)
|-
| Architektur || Ampere
|-
| GPU || GA102
|-
| GPU-Subtyp || GA102-300-A1
|-
| Die-Größe || 6,28 cm²
|-
| Cachegröße (L1) || 128 KiB pro Streaming Multiprocessor
|-
| Cachegröße (L2) || 6 MiB
|-
| Baugröße || 8 Nanometer
|-
| Transistormenge || 28,3 Milliarden
|-
| Slotbreite || 3 Slots
|-
| Abmessungen || 336 mm x 140 mm x 61 mm
|-
| Kerne (Shader)|| 10496
|-
| Texture Mapping Units || 328 (≙ Tensor-Kerne)
|-
| Render Output Units || 112
|-
| Streaming Multiprocessors || 82 (≙ Raytracing-Kerne)
|-
| Grafikspeicher || 24576 MiB
|-
| Grafikspeichertyp || GDDR6X
|-
| Busbreite || 384 bit
|-
| Schnittstelle || PCIe 4.0 (x16)
|-
| Basistakt || 1,395 GHz (Memory: 1,219 GHz)
|-
| Boosttakt || 1,695 MHz
|-
| Bandbreite Speicher || 936,2 GB/s
|-
| Thermal Design Power || 350 Watt
|-
| Anschlüsse || 3x DisplayPort 1.4a; 1x HDMI 2.1
|-
| CUDA-Version || 8.6
|-
| DirectX-Version || 12 Ultimate/12_2
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 6.6
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 189,8 Gigapixel/Sekunde
|-
| Texturrate || 556,0 Gigatexel/Sekunde
|-
| FP16-Leistung (half) || 35,58 TeraFLOPS
|-
| FP32-Leistung (float) || 35,58 TeraFLOPS
|-
| FP64-Leistung (double) || 556,0 GigaFLOPS
|-
| Generation Raytracing-Kerne || 2. Generation
|-
| Generation Tensor-Kerne || 3. Generation
|-
| Deep Learning Super Sampling || Ja
|-
| NVIDIA Encoder || 7. Generation
|-
| NVIDIA Decoder || 5. Generation
|-
| Maximal unterstützte Auflösung || 7680 x 4320 Pixel (@ 60 Hz, 12-Bit-HDR mit DP 1.4a und DSC), 3840 x 2160 Pixel (@ 240 Hz, 12-Bit-HDR mit DP 1.4a und DSC)
|-
| Maximal unterstützte Bildschirme || 4
|-
| Maximal zulässige Temperatur || 93 °C
|}
{| class="wikitable"
|+ Spezifikationen Intel Core i9-10900K<ref>https://ark.intel.com/content/www/us/en/ark/products/199332/intel-core-i910900k-processor-20m-cache-up-to-5-30-ghz.html</ref>
|-
! Typ !! Wert
|-
| Name || Intel® Core™ i9-10900K Processor
|-
| Lithografie || 14 nm
|-
| UVP (USA) || 488 $
|-
| Kerne/Threads || 10/20
|-
| Basistakt || 3,70 GHz
|-
| Turbotakt || 5,30 GHz
|-
| Cache || 20 MiB
|-
| Busgeschwindigkeit || 8 GigaTransfer/s
|-
| Thermal Design Power || 125 Watt
|-
| Maximal unterstützte RAM-Kapazität || 128 GiB
|-
| DDR-Generation || DDR4
|-
| GPU-Recheneinheit || Intel UHD Graphics 630
|-
| GPU-Basistakt || 350 MHz
|-
| GPU-Maximaltakt || 1,20 GHz
|-
| Maximal unterstützte Auflösung || 4096 x 2160 (30 Hz) @ HDMI / 4096 x 2304 (60 Hz) @ DP
|-
| T<sub>Junction</sub> (maximal zulässige Die-Temperatur) || 100 °C
|-
| Abmessungen || 37,5 mm x 37,5 mm
|-
| Architekturbreite || 64-Bit
|}
{| class="wikitable"
|+ Spezifikationen AMD Ryzen 9 5950X<ref>https://www.amd.com/de/products/cpu/amd-ryzen-9-5950x</ref><ref>https://www.amd.com/en/product/10456</ref>
|-
! Typ !! Wert
|-
| Kerne/Threads || 16 Kerne, 32 Threads
|-
| Basistakt || 3,4 GHz
|-
| Boosttakt || 4,9 GHz
|-
| Cache || 72 MiB (8 MiB L2 + 64 MiB L3)
|-
| Thermal Design Power || 105 W
|-
| Baugröße || 7 Nanometer
|-
| Preis (UVP) ||
|-
| Codename || Vermeer
|-
| Architektur || Zen 3 / AM4 (CPU-Sockel)
|-
| Release || 11/5/2020
|}
<gallery>
Rendering 8K 20220821 RGB16.png|2020 ging es einen großen Schritt Richtung 8K im Alltag
Rückseite Galaxy S20 Ultra 20200305.jpg|Das S20 Ultra mit 8K-Aufnahmefunktion
Flipper Zero.jpg|Klein aber oho – Das weiß-orange Gadget
Gigabyte GeForce RTX 3090 Eagle OC 24G, 24576 MiB GDDR6X Front Transparent 20201116.png|Eine Custom-Edition der RTX 3090
Samsung 870 QVO 8TB SATA 2,5 Zoll Internes Solid State Drive (SSD) (MZ-77Q8T0BW) 20211008 Rückseite SSD022corr.png|SSD können nun für die Endkundschaft 8TB groß sein
AMD Ryzen 7 5800X 19339.jpg|Ein Modell der 5000er-Reihe
</gallery>
===2021===
* Q1 2021: Die Intel Core iX-Prozessoren der 11. Generation erscheinen
* 05.01.2021: Mit DALL-E und DALL-E 2 veröffentlicht OpenAI Modelle des maschinellen Lernens, die Bilder generieren. Der Abkömmling Craiyon erzeugt gemäß einer Eingabe eines Menschen eine Reihe von Bildern. Beliebt sind ungewöhnliche Konstellationen, wie ein Astronaut, der auf einem Pferd reitet.
* 14.01.2021: Das Samsung Galaxy S21 erscheint.
* 05.2021: Uwuntu erscheint.<sub>Anhand der Versionsnummer 21.05 wird geschätzt, dass 05.2021 das Release-Date war</sub>
* 17.09.2021: Das iPhone 14 erscheint.
* 05.10.2021: Microsoft Windows 11 erscheint.
* 04.11.2021: Intel bringt Prozessoren der Alder-Lake-Architektur (12XXX) heraus. Kennzeichen ist der heterogene Stil der Kerne (umformulieren).<ref>https://www.golem.de/news/alder-lake-intel-will-mit-241-watt-an-die-spitze-2110-160622.html</ref>
* 11.2021/12.2021: Mit der Seagate Exos X20 kommt eine der ersten 20-TB-Festplatten auf den Markt für die Endkundschaft. Die Festplatte basiert auf der CMR-Technik.<ref>https://www.seagate.com/files/www-content/datasheets/pdfs/exos-x20-channel-DS2080-2111DE-de_DE.pdf</ref> Verglichen mit der 1-TB-Festplatte aus 2007 hat sich der Speicher in 14 Jahren um den Faktor 20 vergrößert und folgt damit nicht mehr dem Mooresschen Gesetz wie früher. Mit 789 € UVP war der Preis hoch, aber er sinkt auf etwa 320-330 € im März 2024.
* Wissenschaftler erzeugen ein DNA-Schreibegerät, das mit 18 Mbps auf DNA schreibt.<ref>[[w:en:DNA digital data storage]]</ref> DNA als Speicher birgt großes Speicherpotenzal, momentan jedoch sind Schreib- und Lesegeschwindigkeit sehr gering und für den Massenmarkt unrentabel.
* Die ersten DDR5-RAM-Riegel erscheinen<ref>https://www.gamingguru.de/blog/ddr5-ram/</ref>
{| class="wikitable"
|+ Systemvoraussetzungen für Windows 11
|-
! Überschrift !! Überschrift
|-
| System || UEFI-PC mit Version 2.3.1 und Secure Boot
|-
| CPU || Dual-CPU mit 1 GHz (64-bit)
|-
| TPM || Trusted Platform Module 2.0
|-
| RAM || 4 GiB
|-
| Grafik || DirectX 12 mit WDDM-2.0-Treiber, 1280x720 Pixel
|-
| HDD || 64 Gigabyte (vorzugsweise SSD)
|}
{| class="wikitable"
|+ Spezifikationen Intel Core i9-11900K<ref>https://ark.intel.com/content/www/us/en/ark/products/212325/intel-core-i911900k-processor-16m-cache-up-to-5-30-ghz.html</ref>
|-
! Typ !! Wert
|-
| Name || Intel® Core™ i9-11900K Processor
|-
| Lithografie || 14 nm
|-
| UVP (USA) || 539 $
|-
| Kerne/Threads || 8/16
|-
| Basistakt || 3,50 GHz
|-
| Turbotakt || 5,30 GHz
|-
| Cache || 16 MiB
|-
| Busgeschwindigkeit || 8 GigaTransfer/s
|-
| Thermal Design Power || 125 Watt
|-
| Maximal unterstützte RAM-Kapazität || 128 GiB
|-
| DDR-Generation || DDR4
|-
| GPU-Recheneinheit || Intel UHD Graphics 750
|-
| GPU-Basistakt || 350 MHz
|-
| GPU-Maximaltakt || 1,30 GHz
|-
| Execution Units || 32
|-
| Maximal unterstützte Auflösung || 4096 x 2160 (60 Hz) @ HDMI / 5120 x 3200 (60 Hz) @ DP
|-
| T<sub>Junction</sub> (maximal zulässige Die-Temperatur) || 100 °C
|-
| Abmessungen || 37,5 mm x 37,5 mm
|-
| Architekturbreite || 64-Bit
|}
<gallery>
DALL-E 2 artificial intelligence digital image generated photo.jpg|Die Kreativität bald die einzige Grenze? Teddybären nutzen unter Wasser Hardware
GalaxyS21.png|Die verschiedenen Smartphones der S21-Reihe
VirtualBox Uwuntu 21.05 22 08 2022 12 50 53.png|Uwuntu-Desktop
IPhone 13 Pro wordmark.svg|Das Logo des iPhone 13 Pro
Back of the iPhone 13 Pro.jpg|Rückseite des iPhone 13 Pro mit Kameras
Windows 11 logo.svg|Das Logo von Windows 11 ist schlicht gehalten
DDR5 SDRAM IMGP6295 smial wp.jpg|DDR5-RAM bietet mehr Speicherkapazität und Taktraten jenseits der 4 GHz
Seagate Exos X20 20 TB 20240316 HOF01100 RAW-Export 000472.png|20 Terabyte – 2 Millionen mal mehr Speicherplatz als die ersten Festplatten hatten
</gallery>
===2022===
* Mit dem Bild "Théâtre D’opéra Spatial" gewinnt ein Teilnehmer einen Bilderwettbewerb. Aufgrund der Tatsache, dass die Datei zu größten Teilen von einer Künstlichen Intelligenz generiert wurde, wird dem Bild kein Urheberrechtsschutz eingeräumt.
* 25.02.2022: Mit dem Steam Deck veröffentlicht Valve einen tragbaren Personal Computer, auf dem man Computerspiele spielen kann.
* 08.03.2022: AMD veröffentlicht den AMD Ryzen™ Threadripper™ PRO 5995WX. Diese Workstation-CPU ist ein 64-Kerner mit 128 Threads. Basistakt sind 2,7 GHz, maximale Taktrate sind 4,5 GHz. Mit einer Leistungsaufnahme von 280 Watt macht diese Recheneinheit selbst Grafikkarten Konkurrenz.
* 11.03.2022: Die Samsung-Galaxy-S22-Reihe erscheint vollständig
* 06.2022: Der Supercomputer Frontier geht ans Netz. Er ist einer der ersten Supercomputer mit einer Spitzenleistung von einem ExaFLOPS (1,1 ExaFLOPS). Er führt offiziell die TOP500-Liste an.
* 10.05.2022: AMD veröffentlicht die AMD Radeon RX 6950 XT
* 21.07.2022: Das Nothing Phone (1) erscheint. Sein OS basiert auf Android.
* 08.2022: Western Digital bietet für 599,99$ 22-TB-Festplatten (SATA) an.<ref>https://www.westerndigital.com/products/internal-drives/wd-gold-sata-hdd#WD221KRYZ</ref>
* 10.08.2022: Microsoft veröffentlicht seine Fluent-Emoji-Serie unter der MIT-Lizenz.<ref>https://github.com/microsoft/fluentui-emoji</ref><ref>https://github.com/microsoft/fluentui-emoji/blob/main/LICENSE</ref>
* 22.08.2022: Mit [[w:en:Stable Diffusion]] erscheint ein weiteres Deep-Learning-Modell, das Texte in ein Bild umsetzt. Durch die Konkurrenz von KI, schöpferische Werke zu entwickeln, befürchtet die Kreativindustrie, dass Umsätze durch schöpferische Werke bald so nicht mehr möglich sein werden, da künstliche Intelligenz diese Arbeit mehr und mehr alleine ausführen kann. Auch steigt durch mehr Leistung die Qualität der Ergebnisse über die Zeit. Das Bild unten zeigt eine fiktive Fotografie eines auf einem Pferd reitenden Astronauten. Braucht es also bald Fotografen und weitere Kunstschaffende bald nicht mehr (zu kommerziellen Zwecken)? Des Weiteren werden Parallelen zu dem Zeitpunkt gezogen, wo die Fotografie Maler ersetzte. Ab dem 19. Jahrhundert mussten Porträts nur noch fotografisch geschossen werden, nicht mehr gemalt.
* 30.08.2022: AMD stellt die AMD Ryzen 7000-Serie vor. Deutlich wird die stärkere Leistung gegenüber der Intel Core iX 12000-Reihe.
* 12.10.2022: NVIDIA GeForce RTX 4090 erscheint. Durch die Fähigkeiten der Tensor-Kerne, Raytracing, der starken Rechenleistung, Automatisierung und Generierung von fotorealistischen Inhalten, könnte der Arbeitsalltag bald ganz anders aussehen und viele Arbeitsplätze obsolet machen. Die Karte erlaubt Dual-AV1-Encoder und 8K-Videoaufnahme bei 60 FPS. Kritisiert jedoch wird NVIDIAs Preispoitik, die Verwirrung um RTX 4080 12GB und 16GB und u.a. der hohe Stromverbrauch der RTX 4090, der in Zeiten von Inflation, hohen Strompreisen und Klimaproblemen unverantwortlich sei.<ref>https://www.heise.de/meinung/Kommentar-zu-RTX-4000-Grafikkarten-Nvidia-wen-wollt-Ihr-veralbern-7273912.html</ref>
* 30.11.2022: Das von OpenAI bereitgestellte und proprietäre ChatGPT wird für die Öffentlichkeit zur Verfügung gestellt. Es ist ein Chatbot auf KI-Basis, der Antworten auf diverse Fragestellungen gibt. Er wird vor allem in sozialen Netzwerken populär und wirft die Frage auf, welche Rolle diese bei der Lösung von Aufgaben wie Hausaufgaben spielen wird und wie damit umzugehen ist. Außerdem setzen manche den Fokus auf die Glaubwürdigkeit der Antworten, so fehlen mit Stand November 2022 meist Quellenangaben oder stützende Nachweise des Bots. Der Hype um KI verbreitet sich in der Gesellschaft deutlich. Unternehmen mit Fokus auf KI wachsen teils stark und es baut sich die KI-Blase auf. Manche ziehen einen Vergleich zur Dotcom-Blase in den 1990ern.
* Dezember 2022: Die AMD Radeon RX 7900 XT und Radeon RX 7900 XTX kommen auf dem Markt.
* PCIe 6.0 wird eingeführt. Die Transferrate pro Lane beträgt 64 Gigatexel/s und der Datendurchgang bis zu etwa 121 GiB/s.
* Mit der Ultrastar DC HC670 (ultrastar-dc-hc670-26-tb) von Western Digital erscheint eine der ersten 26-TB-Festplatten für Rechenzentren (Unternehmensbereich). Die Platte hat 10 Magnetplatten (2,6 TB pro Platte) und basiert auf SMR.
{| class="wikitable"
|+ Spezifikationen AMD Ryzen 9 7950X<ref>https://www.amd.com/de/products/cpu/amd-ryzen-9-7950x</ref>
|-
! Typ !! Wert
|-
| Kerne/Threads || 16 Kerne, 32 Threads
|-
| Basistakt || 4,5 GHz
|-
| Boosttakt || 5,7 GHz
|-
| Cache || 80 MiB (L2+L3)
|-
| Thermal Design Power || 170W
|-
| Baugröße || 5 Nanometer
|-
| Preis (UVP) || 699 US-$
|-
| Codename || Raphael
|-
| Architektur || Zen 4
|-
| Release || 27.09.2022
|}
{| class="wikitable"
|+ Spezifikationen AMD Radeon RX 6950 XT<ref>https://www.techpowerup.com/gpu-specs/radeon-rx-6950-xt.c3875</ref>
|-
! Typ !! Wert
|-
| Hersteller || AMD
|-
| Erscheinungsdatum || 10.05.2022
|-
| Plattform || Navi
|-
| Generation || RDNA 2.0
|-
| Architektur || RDNA 2.0
|-
| GPU || Navi 21
|-
| GPU-Subtyp || Navi 21 KXTX (215-121000289)
|-
| Die-Größe || 5,2 cm²
|-
| Cachegröße (L0) || 32 KiB pro WGP
|-
| Cachegröße (L1) || 128 KiB pro Array
|-
| Cachegröße (L2) || 4 MiB
|-
| Cachegröße (L3) || 128 MiB
|-
| Baugröße || 7 Nanometer
|-
| Transistormenge || 26,8 Milliarden
|-
| Slotbreite || 3 Slots
|-
| Abmessungen || 267 mm x 120 mm x 50 mm
|-
| Kerne (Shader)|| 5120
|-
| Texture Mapping Units || 320
|-
| Render Output Units || 128
|-
| Compute Units || 80
|-
| Raytracing-Kerne || 80
|-
| Grafikspeicher || 16384 MiB
|-
| Grafikspeichertyp || GDDR6
|-
| Busbreite || 256 bit
|-
| Schnittstelle || PCIe 4.0 (x16)
|-
| Basistakt || 1,925 GHz (Memory: 2,250 GHz)
|-
| Boosttakt || 2,324 GHz (Spieltakt: 2,116 GHz)
|-
| Bandbreite Speicher || 576 GB/s
|-
| Thermal Design Power || 335 Watt
|-
| Anschlüsse || 2x DisplayPort 1.4a; 1x HDMI 2.1
|-
| DirectX-Version || 12 Ultimate/12_2
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 2.1
|-
| Shader-Version || 6.5
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 297,5 Gigapixel/Sekunde
|-
| Texturrate || 743,7 Gigatexel/Sekunde
|-
| FP16-Leistung (half) || 47,60 TeraFLOPS
|-
| FP32-Leistung (float) || 23,80 TeraFLOPS
|-
| FP64-Leistung (double) || 1487 GigaFLOPS
|-
|}
{| class="wikitable"
|+ Spezifikationen NVIDIA GeForce RTX 4090<ref>https://www.youtube.com/watch?v=fj245xMr-BM</ref><ref>https://www.nvidia.com/de-de/geforce/graphics-cards/40-series/rtx-4090/</ref>
|-
! Typ !! Wert
|-
| Hersteller || NVIDIA
|-
| Erscheinungsdatum || 12.10.2022
|-
| Plattform || GeForce RTX
|-
| Generation || RTX 40(00)
|-
| Architektur || Ada Lovelace
|-
| GPU || AD102
|-
| GPU-Subtyp || AD102-300-A1
|-
| Die-Größe || 609 mm²
|-
| Cachegröße (L1) || 128 KiB (pro SM)
|-
| Cachegröße (L2) || 72 MiB
|-
| Baugröße || 5 nm (Transistor)
|-
| UVP || 1599 US-$ / 1949 €
|-
| Transistormenge || 76,3 Mrd.
|-
| Slotbreite || 3 Slots
|-
| TDP || 450 W
|-
| Abmessungen || (304 x 137 x 61) mm³
|-
| Kerne (Shader)|| 16384
|-
| Texture Mapping Units || 512
|-
| Render Output Units || 176
|-
| Streaming Multiprocessors || 128
|-
| Grafikspeicher || 24576 MiB
|-
| Grafikspeichertyp || GDDR6X
|-
| Busbreite || 384 Bit
|-
| Schnittstelle || PCIe 4.0 x16
|-
| Basistakt || 2,23 GHz
|-
| Boosttakt || 2,52 GHz
|-
| Bandbreite Speicher || ca. 1 TB/s
|-
| Thermal Design Power || ca. 450 Watt
|-
| Anschlüsse || 1x HDMI 2.1 / 3x DisplayPort 1.4a
|-
| CUDA-Version || 8,9
|-
| DirectX-Version || 12 Ultimate (12_2)
|-
| OpenGL-Version || 4.6
|-
| OpenCL-Version || 3.0
|-
| Shader-Version || 8.9 (CUDA)
|-
| Vulkan-Version || 1.3
|-
| Pixelfüllrate || 443,5 Gigapixel/s
|-
| Texturrate || 1290 GTexel/s
|-
| FP16-Leistung (half) || 82,58 TFLOPs
|-
| FP32-Leistung (float) || 82,58 TFLOPs
|-
| FP64-Leistung (double) || 1290 GFLOPs
|-
| Leistungen (andere) || 83 Shader-TFLOPS, 191 RT-TFLOPS, 1320 Tensor-TFLOPS
|-
| Generation Raytracing-Kerne || 3. Generation (+ Shader Execution Reordering)
|-
| Generation Tensor-Kerne || 4. Generation
|-
| Deep Learning Super Sampling || Ja (3. Generation)
|-
| Unterstützt || NVIDIA DLSS (3rd Gen), NVIDIA Reflex, NVIDIA Broadcast, PCIe Gen4, resizable BAR, NVIDIA GeForce Experience, NVIDIA Ansel, NVIDIA Freestyle, NVIDIA ShadowPlay, NVIDIA Highlights, NVIDIA G-SYNC, Game Ready-Treiber, NVIDIA Studio-Treiber, NVIDIA Omniverse, NVIDIA GPU Boost, AV1-Encoding/-Decoding, VR Ready
|-
| NVIDIA Encoder || 2x 8. Generation
|-
| NVIDIA Decoder || 5. Generation
|-
| Maximal unterstützte Auflösung || 7680 x 4320 (@ 12-Bit HDR, 60 FPS mit DP 1.4a bzw. HDMI 2.1 + DSC/@ 12-Bit HDR, 120 FPS mit 2x DP 1.4a), 3840 x 2160 (@ HDR und 120 FPS, HDMI 2.1a)
|-
| Maximal unterstützte Bildschirme || 4 (HSCP 2,3)
|-
| Maximal zulässige Temperatur || 90 °C
|}
<gallery>
Théâtre D’opéra Spatial.jpg|Traditionelle Tracht und Fiktion - KI macht es möglich
Steam Deck (front).png|Das Steam Deck
SAMSUNG Galaxy S22 Ultra BLACK (3).jpg|Die Kameras des S22 Ultra
Frontier Supercomputer (3).jpg|Einer der schnellsten Kaliber seiner Zeit: Der Frontier
Fluent Emoji Color 1f3db-fe0f.svg|Emojis sind nun unter einer Open-Source-Lizenz nutzbar
A depiction of an astronaut riding a horse 2022-08-28.png|Ein Astronaut auf einem Pferd: Deep-Learning-Modelle machen es möglich
Nothing Phone 1 wordmark.svg|Logo des Nothing Phone (1) als Dot-Matrix
Nothing phone(1) White.svg|Das Nothing Phone (1): In jeglicher Hinsicht besser als nichts
Nothing phone(1) White (back).svg|Die Rückseite des Nothing Phone (1), die es so besonders macht
Nvidia@5nm@AdaLovelace@AD102@GeForce RTX 4090@S TW 2324A1 U2F028.MOW AD102-301-A1 DSCx3@VIS.jpg|Die Leiterplatte einer NVIDIA GeForce RTX 4090
</gallery>
===2023===
* Aufgrund von Verwerfungen nimmt ein Großteil aller NFTs einen Wert von 0 ETH an, was sie wertlos macht.<ref>https://futurezone.at/digital-life/nft-preis-handel-wertverlust-hype-ether-bored-ape-yacht-club-dappgambl-krypto/402602591</ref>
* Der Begriff "Brainrot" für durch Gehirnfäule getätigte Begrifflichkeiten gewinnt massiv an Popularität, unter anderem auf TikTok.
* 14.03.2023: Das Sprachmodell GPT-4 erscheint. Es wird für ChatGPT eingesetzt. Aufgrund der Fähigkeiten sehen es manche als Beginn der AGI (künstliche generelle Intelligenz). Andere sind von der multimodalen Leistung beeindruckt, wiederum andere sorgen sich darum, dass aufgrund des schnellen Fortschritts KI außer Kontrolle geraten könnte. Modelle wie GPT 3.5 oder GPT 4 sind proprietär und Closed source. Jedoch wird Open Source-LLMs langfristig mehr Potenzial eingeräumt.
* In den USA soll zum ersten Mal ein Anwalt auf Basis von künstlicher Intelligenz eingesetzt werden.<ref>https://www.pcwelt.de/article/1469241/ki-anwalt-vertritt-erstmals-angeklagten-vor-gericht.html</ref>
* 12.05.2023: The Legend of Zelda: Tears of the Kingdom erscheint. Passend dazu erscheint am 28.04.2023 eine Nintendo Switch als OLED-Modell im TotK-Stil. Das Spiel gilt als erfolgreich, wie man an den Verkauszahlen ablesen kann.
* 01.08.2023: Das Muster der 28-TB-HDD wird angekündigt.<ref>https://www.computerbase.de/2023-08/western-digital-715-mio-usd-verlust-und-die-erste-28-tb-festplatte/</ref>
* 29.08.2023: Google lässt KI-Chips (TPU-Chips) maßgeblich an der Produktion von TPU-Chips der kommenden Generation mitwirken. Überzeugen kann die KI durch die Schnelligkeit und bessere Leistung im Vergleich zu seinen menschlichen Pendants. Dies ist ein maßgeblicher Schritt zur technologischen Singularität, wo künstliche Intelligenzen selbst immer optimiertere Hardware oder KI-Systeme realisieren, wodurch sich der Anstieg der Hardwareleistung unfassbar stark beschleunigen könnte.<ref>https://www.heise.de/news/Google-TPU-KI-Chip-berechnet-seinen-eigenen-Nachfolger-9287632.html</ref>
* ca. 10.2023: Unter der Marke "HYTE" wird ein Gehäuse mit äußerem hochauflösendem, länglichen Display veröffentlicht. Es wird relativ beliebt und stellt eine Möglichkeit dar, wie Computer in naher Zukunft häufiger aussehen können. Der Gehäusestil wird immer mehr ein Individualitätsmerkmal eines Computers.
* 18.10.2023: Microsoft arbeitet an "Project Silica". Hierbei handelt es sich um einen robusten Quarzglasspeicher. Ziel ist der Einsatz in Datacentern, Speicherdauern jenseits der 1000 Jahre und etliche Terabyte Speicherplatz. Gespeichert werden sollen Informationen als Voxel.<ref>https://www.computerbase.de/2023-10/update-zu-project-silica-microsofts-cloud-speicher-der-zukunft-setzt-auf-glas/</ref><ref>https://www.microsoft.com/en-us/research/project/project-silica/</ref>
* 19.10.2023: AMD stellt die Workstation- und HEDT-CPUs (High-End-Desktop) Ryzen Threadripper 7000(-Pro) vor. Sie teilen die Eigenschaften der Zen-4-Kerne, DDR5-RAM-Support, PCI-Express-5.0 und mehr. Die 7995WX soll 96 Kerne und 192 Threads schaffen. Die Workstation-CPU ist eine der ersten mit 96 Kernen und 192 Threads. Die UVP der CPU liegt über 10.000 €. Alle CPUs haben eine TDP von 350 W. Ab dem 21. November 2023 soll man diese Prozessoren kaufen können.<ref>https://www.golem.de/news/workstation-und-hedt-amd-stellt-ryzen-threadripper-7000-vor-2310-178638-2.html</ref>
* 11.2023: Der Supercomputer {{w|Aurora (supercomputer)}} wird in Betrieb genommen. Der Betreiber ist das Argonne National Laboratory. Die Leistung soll etwa 1,09 ExaFLOPs betragen, was ihn zum Exascale-Supercomputer macht. Der Stromverbrauch soll 24,6 Megawatt betragen. Das entspricht etwa 70285,7 RTX 3090-Grafikkarten.
* 26.11.2023: Unter dem Markennamen Cerabyte will die Ceramic Data Solutions Holding GmbH aus München langlebige Datenträger (5000 Jahre) mit 10 Petabyte bis 2030 etablieren. Hierbei handelt es sich um keramikummanteltes Glas.<ref>https://www.pcgameshardware.de/Wissenschaft-Thema-237118/News/Cerabyte-Optische-Speichertechnik-unverwuestlich-5000-Jahre-1434756/</ref><ref>https://blocksandfiles.com/2023/11/22/cerabyte-demonstration-system/</ref> Die Angaben sind sehr ambitioniert. In der Vergangenheit wurden schon hohe Prognosen in Bezug auf die Datenträger der Zukunft geliefert, die jedoch stark verfehlt wurden. Für 10 Petabyte bräuchte man heute (12.2023) etwa 500 HDDs.
* 12.2023: Seagate bringt eine der ersten 24-TB-HDDs in der Breite raus (Seagate Exos X24). Gleichzeitig ist sie einer der letzten CMR-Festplatten (Conventional Magnetic Recording/PMR), die folgenden Platten (ab 2024) sollen HAMR (Heat-Assisted Magnetic Recording) aufweisen. Enterprises können SMR-Platten (Shingled Magnetic Recording) mit 28 TB erwerben. Die 24-TB-Platte soll maximal 285 MB/s schaffen.<ref>https://www.computerbase.de/2023-10/seagate-exos-x24-erste-24-tb-festplatte-kommt-mit-28-tb-option/</ref>
* 04.12.2023: IBM stellt das IBM Quantum System Two vor. Hierbei handelt es sich um ein modulares Quantencomputersystem. Zwar werden Quantencomputer immer komplexer, allerdings sind sie weiterhin nicht alltagstauglich. So brauchen sie üblicherweise eine Betriebssystemperatur wenige Kelvin über dem Nullpunkt.
* 20.12.2023: Kioxia kündigt eine der ersten 2-TB-MicroSDXC-Karten für den Endmarkt ein. Geplant ist ein Marktstart in Q1 2024. MicroSD-Karten mit mehr Speicherkapazität fallen unter die SDUC-Spezifikation.<ref>https://www.computerbase.de/2023-12/speicherkarten-kioxia-erreicht-mit-2-tb-das-maximum-von-microsdxc/</ref>
* Nennenswerte CPUs erscheinen
* Durch LLMs und weitere KI-Agenten wird viel '''AI Slop''' generiert und damit sogenannte "soziale Netzwerke" geflutet. Der Anteil an KI-generierte, teils abstruser Werke, wächst enorm, und zeichnet nicht reale Abbildungen. Gerade wenig reflektierende Menschen fallen auf diese Fakes herein und betrachten sie als real. Sollte der Trend weitergehen, so wird ein Großteil aus KI-Inhalten bestehen, was einen noch größeren Anteil an unrealistischen Inhalten und Fakes in den Netzwerken erzeugt. Hiermit werden die "sozialen Netzwerke" zu noch größeren Katalysatoren und Dreckschleudern von Fake News.<ref>https://www.theguardian.com/commentisfree/2025/apr/21/ai-slop-artificial-intelligence-social-media</ref> Da Medien in auf den Plattformen stark komprimiert werden, können KI-Artefakte durch Kompressionsartefakte überdeckt sein. Um "Unsinn", also auf KI-Inhalte hinweisende Elemente zu erkennen, kann es helfen, die Quelle der Medien zu suchen, auf unsinnigen Text zu prüfen, physikalische Ungenauigkeiten zu finden, oder unproportionale Inhalte.
<gallery>
Nintendo Switch – OLED-Modell (The Legend of Zelda - Tears of the Kingdom) 20230510 HOF02399 RAW-Export.png|Die "Zelda-Switch"
Unveiling IBM Quantum System Two.webm|IBM stellt ihr IBM Quantum System Two vor
Unterseite des AMD Ryzen Threadripper 7970X 20240407 074.jpg|Der Threadripper 7970X mit 32 Kernen und viel Power – wortwörtlich
Monochrome HYTE Y70 Touch Custom Loop Water Cooling PC Build.webm|Computergehäuse mit eigenem Display; bald der Standard?
</gallery>
===2024===
* 01.2024: Seagate stellt seine Modellreihe "Exos Mozaic 3+" vorher. Hierbei handelt es sich um Festplatten mit SMR (Shingled Magnetic Recording) und Kapazitäten von bis zu 32 Terabyte pro Festplatte.
* 23.01.2024 (ca.): Das "Mother of all breaches"-Datenleck wird bekannt. Es handelt sich um mehr als 26 Milliarden Datensätzen von Nutzeraccounts etc. Es wird angenommen, dass es einer der größten Datenlecks aller Zeiten ist (mit über 12 Terabyte)<ref>https://cybernews.com/security/billions-passwords-credentials-leaked-mother-of-all-breaches/</ref>. Ob in Zukunft sich noch persönliche Daten zuverlässig schützen lassen, ist fraglich.
* 29.01.2024: Der Multimilliardär Musk verkündet die Implantierung eines Neuralink-Implantat in einem Menschen. Hierbei soll digitale Technik mit dem Gehirn interagieren. Das Potenzial ist enorm, weshalb es auch kritisch beäugt wird.
* 02.2024: Das Unternehmen OpenAI präsentiert Sora, ein Text-zu-Video-KI-Modell. Es generiert ein ziemlich realistisches Video aus einem Prompt. Die Auswirkungen sind schwer vorhersehbar; von Veränderungen in der Kreativwirtschaft, bis hin zur Generierung von Fakes und Manipulationen, und der Erweiterung einer Möglichkeit, sich kreativ zu auszuleben. Richtig eingesetzt kann diese Technologie viel bringen, aber es wird wichtig bleiben, KI-generierte Werke von "echten" Werken unterscheiden zu können. Der technologische Fortschritt in generativer KI wirkt sehr schnell.
* 02.02.2024: Apple veröffentlicht das {{w|Apple Vision Pro}}. Es ist ein Headset für Augmented und Virtual Reality. Ob es sich durchsetzt, ist fraglich, so wird der Preis, die kurze Akkulaufzeit oder die Unhandlichkeit kritisiert.<ref>https://nrodlzdf-a.akamaihd.net/none/zdf/24/02/240208_2315_sendung_mla/1/240208_2315_sendung_mla_6660k_p37v17.mp4</ref>
* 06.02.2024: Solidigm möchte mit dem Ausliefern ihrer 61,44-Terabyte-SSDs beginnen. Die SSD (SSD D5-P5336) soll im 2,5"-Format daherkommen und 5190 € inklusive Steuern kosten. Sinkt der Preis um 80-90 %, so wird er für die Endkundschaft auch erschwinglich.<ref>https://www.heise.de/news/Die-erste-SSD-mit-61-44-TByte-Speicher-ist-vorbestellbar-9604707.html</ref>
* Gegen Ende 2024 soll der DDR6-Standard starten. Zum Einsatz soll er im Enterprise-Bereich 2025 zuerst kommen.
* 21.02.2024: Es wird bekannt, dass das USST bei dem "Green Optical Big-Data Storage" (oder "3D nanoscale optical disk memory with petabit capacity) vorankommt. Der optische Datenträger soll 200 Terabyte an Speicher haben. Eine baldige Marktfähigkeit wird jedoch bezweifelt. Datenträger, Lese- und Schreibgerät müssten verbreitet werden, und auch Faktoren wie Datensicherheit, Haltbarkeit und Schreib- und Lesegeschwindigkeit spielen eine Rolle.<ref>https://en.usst.edu.cn/info/1023/2901.htm</ref>
* 06.03.2024: JEDEC veröffentlicht den GDDR7-Standard. Hiermit sollen Geschwindigkeiten von bis zu 48 GBit/s möglich sein. Bei einem 512-Bit-Speicherinterface wären Datenraten von bis zu 3,072 Terabyte pro Sekunde möglich.<ref>https://www.jedec.org/standards-documents/docs/jesd239#</ref><ref>https://www.golem.de/news/doppelt-so-schnell-wie-gddr6x-gddr7-soll-bis-zu-48-gbit-s-erreichen-2403-182915.html</ref>
* 09.03.2024: Die Rechteinhaber an den menschlichen Eigenschaften Marilyn Monroes verwerten Teile von ihr kommerziell über eine Generative Pretrained Transformer. Hierbei stellt sich die Frage, ob die ethischen und moralischen Grenzen des Gelderwerbs überschritten werden.<ref>https://www.heise.de/news/Rechteinhaber-lassen-Marilyn-Monroe-per-ChatGPT-auferstehen-9650578.html</ref>
* 13.03.2024: Die Europäische Union bringt das erste "KI-Gesetz" der Welt zustande.<ref>https://www.tagesschau.de/ausland/europa/eu-ki-gesetz-100.html</ref><ref>zdf.de/nachrichten/politik/ausland/ai-act-ki-eu-parlament-gesetz-100.html</ref>
* 29.03.2024: Der ITler Andres Freund entdeckt eine Backdoor in der Linux-Software xz. Diese Sicherheitsbeeinträchtigung wird unter der Bezeichnung "CVE-2024-3094" geführt.
* 17.05.2024: Das Pew Research Center veröffentlich eine Studie, die besagt, dass 38 % der Webseiten von 2013 ab etwa Oktober 2023 nicht mehr verfügbar waren. Man könnte von einer "Amnesie des World Wide Web" sprechen. Die Gründe, warum diese Seiten nicht mehr aufrufbar sind, sind mannigfaltig. Unternehmen können Webseiten veralteter Produkte vom Netz nehmen; auf "sozialen Netzwerken" wurden Urheberrechts-, Persönlichkeitsrechts- und andere Verletzungen heruntergenommen, oder Webserver wurden ersatzlos deaktiviert. Während ein Großteil für die Nachwelt wohl weniger bedeutsam ist, so könnten wenige wahre Schätze auch über die Zeit verloren gehen. Internet Archive versuchen, Wichtiges zu bewahren.<ref>https://www.pewresearch.org/data-labs/2024/05/17/when-online-content-disappears/</ref>
* 26.05.2024: Das Schweizer Startup ''FinalSpark'' hat eine der ersten Bioprozessoren entwickelt. Dieser soll viel weniger Energie als ein digitaler Schaltkreis benötigen.<ref>https://www.tomshardware.com/pc-components/cpus/worlds-first-bioprocessor-uses-16-human-brain-organoids-for-a-million-times-less-power-consumption-than-a-digital-chip</ref>
* 06.06.2024: Auf der Computex 2024 kündigt AMD die Ryzen 9000-Serie an. Hiermit will AMD Intel wieder eine starke Konkurrenz bieten. Erscheinen soll die Serie im Sommer 2024.
* 28.06.2024: Japan verbannt endgültig Disketten als Datenträger aus seiner Verwaltung
* 06.2024: Der Frontier-Supercomputer ist mit 1,2 ExaFLOPS (1,2 Trillionen) der gegenwärtig schnellste Supercomputer (TOP500)
* 06.2024: Der Adidas-Fußball "Fußballliebe" enthält Messchips, die bei Verstößen ausgelesen werden können. Manche kritisieren die "Technisierung" des Fußballssports, der von Emotionen lebe.
* 19.07.2024: Durch ein automatisch aufgespieltes fehlerhaftes Update von Crowdstrike wurden viele Windows-Systeme unbrauchbar und ein großer Teil der Infrastruktur brach zusammen. Das Beispiel zeigt gut, wie schnell Netzwerke auch ohne Crackerangriffe lahmgelegt werden können. Betroffen waren unter anderem Flughäfen.
* 20.07.2024: Mitarbeiter des Bayerischen Rundfunks und Netzpolitik.org decken den Handel mit über 3,6 Milliarden Standortdaten auf. Es wirft die Frage auf, ob Datenschutz noch möglich ist, wie viele Leute bereit wären, Datenschutz unter großem zeitlichen Mehraufwand zu bewerkstelligen, oder wie viele es egal ist.<ref>https://www.heise.de/hintergrund/Missing-Link-Wie-Millionen-Bundesbuerger-kommerziell-auspioniert-werden-9805284.html</ref>
* 15.08.2024: AMD stellt mit der AMD Ryzen 9000-Serie eine neue Mikroprozessorgeneration vor
* 11.09.2024: Infineon verkündet die Herrstellung eines 300-Millimeter-Galliumnitrid (GaN)-Wafers. Ziel ist eine höhere Effizienz. Ob die chemische Verbindung langfristig Siliziumwafer ablöst, wird sich zeigen. <!---Fotos erbeten---><ref>https://www.infineon.com/cms/de/about-infineon/press/press-releases/2024/INFXX202409-142.html</ref>
* 08.10.2024: Um 23:11 Uhr (vermutlich US-Amerikanischer Zeit) verkündet der Internet Archive-Gründer Brewster Kahle, dass eine DDoS-Attacke auf das IA stattfand. Es soll Tage dauern, bis das Archiv wieder aufrufbar ist. Bestände sollen laut Angaben der Zuständigen nicht verlorengegangen sein. Am 17.10.2024 war die Wayback Machine wieder erreichbar (Snapshots sind noch nicht möglich). 31 Millionen Konten sollen einen Leak erlitten haben, weshalb, sobald die Server wieder anrufbar sind, die Passwörter geändert werden sollen.<ref>https://www.theverge.com/2024/10/9/24266419/internet-archive-ddos-attack-pop-up-message</ref>
* 24.10.2024: Intel veröffentlicht die Mikroprozessoren der Arrow Lake-Mikroarchitektur (Intel Core Ultra 5/7/9 2XX). Die Leistung bleibt jedoch hinter den Erwartungen zurück. Das Topmodell U9 285K wird mit ca. 650 € auf dem deutschen Markt angeboten. Die Verkaufszahlen sind jedoch niedrig.
* 09.12.2024: Google stellt einen neuen Quantenprozessor "Willow" vor, der die Fehlerrate von Quantencomputern beachtlich senkt und gleichzeitig mehr Qubits aufweist.
* 18.12.2024: Seagate kündigt an, dass 32-TB-Festplatten mit Heat-assisted magnetic Recording bald in Massen verfügbar sind, über die Mozaic 3+-Plattform.<ref>https://www.pcgameshardware.de/Festplatte-Hardware-255553/News/Festplatten-32-TB-HDD-mit-HAMR-von-Seagate-fast-da-1461988/</ref>
<gallery>
The clear glass of Apple Vision Pro.jpg|Die Displays des Apple Vision Pro
Marilyn Monroe, The Prince and the Showgirl, 2.jpg|Von der Schauspielerin zum Produkt: Marilyn Monroe
Ships-in-coffee.webm|Unproblematisches Video: Piratenschiffe auf Kaffee
UEFA Euro 2024 Match Ball Fussballliebe.jpg|Mittlerweile nicht nur Sport- sondern auch Messmittel
Dulles Airport CrowdStruck (53867936421).jpg|Eine böse Überraschung am Flughafen
AMD@4nmCCD(6nmIOD)@Zen5@Granite Ridge@Ryzen 5 9600X@100-000001405 BY 2429SUY 9AEQ579S40073 DSCx14 CCD poly@5xExt.jpg|Die-Shot des AMD Ryzen 5 9600X
Archive-hack-javascrip-pop-up.png|Für kurze Zeit soll bei Aufruf des Archivs so eine Meldung zu sehen gewesen sein
Czy nowe procesory Intela to ULTRA rozczarowanie¿ (2160p 30fps VP9 LQ-128kbit AAC)-00.01.16.400.png|AMD konnte in 2024 mehr überzeugen
</gallery>
===2025===
* Die Amazon Web Services haben zu Stoßzeiten einen Traffic von über 1 PB/s.<ref>https://bigdata.2minutestreaming.com/p/how-aws-s3-scales-with-tens-of-millions-of-hard-drives</ref>
* Die Datenvolumina steigen in dieser Zeit pro Jahr um 30 % (Breitband/Glasfaser)
* In der digitalen Welt ist auch Zensur Alltag. So wurden im Verteidigungsministerium der USA und anderen Regierungswebseiten Inhalte gelöscht, die für Diversität (DEI, LGBTQ, African-Americans und Frauen)<ref>https://www.npr.org/2025/03/07/nx-s1-5321003/pentagon-images-flagged-removal-dei-purge-trump</ref> und Wissenschaft (u.a. Klimaforschung) stehen<ref>https://www.levernews.com/trumps-epa-just-deleted-climate-change/</ref>. Diese Themen werden so zensiert. Verschiedene Organisationen und sogenannte "Data Hoarder" versuchen solche Dateien zu sichern, bevor es zu spät ist
* Anfang Januar stellt NVIDIA seine GeForce RTX 50-Generation vor. Der Fokus wird stark auf KI-Rechenleistung gelegt. Kritisiert werden auch wieder die Preise, und die teils geringen Leistungszuwächse (bspw. RTX 4070 und 5070). Der Fokus auf KI wird auch kritisiert, da viel getrickst würde und viele Anwendungen keine KI benötigen oder gebrauchen können.
* 27.01.2025: Der KI-Assistent von DeepSeek aus China übertrifft ChatGPT als höchstbewertete App. China holt bei Schlüsseltechnologien auf und konkurriert mit kapitalistischen Strukturen in den USA.
* 02.2025: Ein deutsches Unternehmen ermöglicht es, KI auf Faxgeräten zu nutzen und bspw. mit ChatGPT zu kommunizieren. Dies dürfte die Arbeit von vielen Bürostuben erleichtern.<ref>https://t3n.de/news/fax-trifft-ki-deutsche-firma-ermoeglicht-chatgpt-kommunikation-fuer-retro-fans-1670083/</ref>
* 19.02.2025: Microsoft stellt den Quantenprozessor (QPU) "Majorana 1" vor. Er basiert auf topologischen Qubits, und soll 1 MegaQubit umfassen. Er wird als großer Schritt zur Massenanwendung zu Quantencomputern gesehen.<ref>https://news.microsoft.com/de-at/microsoft-stellt-majorana-1-vor-den-weltweit-ersten-quantenprozessor-mit-topologischen-qubits/</ref>
* 17.04.2025: Über sogenannte "PoX" (Phase-change Oxide) haben Forscher der Fudan-Universität nichtflüchtigen Flashspeicher entwickelt, der ein Bit in 400 Pikosekunden schaltet.<ref>https://interestingengineering.com/innovation/china-worlds-fastest-flash-memory-device?group=test_b</ref>
* Mai 2025: Dank Software von Palantir kann die Trump Administration Datensätze von US-Bürgern zusammenführen, und eine Massenüberwachung der Bevölkerung leicht durchführen. <ref>https://www.msnbc.com/top-stories/latest/trump-palantir-surveillance-americans-rcna210017</ref><ref>https://www.nytimes.com/2025/05/30/technology/trump-palantir-data-americans.html</ref> Manche sehen so den Weg in eine Techdiktatur oder einen autoritären Kapitalismus.
* 15.07.2025: Seagate bringt die Seagate Exos M 30 TB für den Endkunden auf den Markt.
* 30.09.2025: AOL stellt die Einwahl in das Internet via Modem und ISDN ein.<ref>https://www.n-tv.de/technik/AOL-beendet-Internet-Einwahl-ueber-Modem-und-ISDN-article25957956.html</ref><ref>https://www.deutschlandfunk.de/aol-stellt-einwahlzugang-per-modem-in-den-usa-ein-100.html</ref>
* Einige KI-Modelle erreichen einen IQ-Wert über 130 und sind damit hochbegabt. Viele KI-Modelle sind intelligenter als ein durchschnittlich intelligenter Mensch.
* ''PCIe 7.0 soll erscheinen. Die maximale Datenrate soll 128,0 Gigatransfers pro Sekunde betragen (bidirektionale Datenübertragungen von 512 GiB/s über x16-Anschlussbreite) und über PAM4-Signal laufen''
* ''Western Digital möchte eine 4-TB-SDUC-Karte auf den Markt bringen<ref>https://www.pcgameshardware.de/Hardware-Thema-130320/News/SD-Karte-4-TB-Kapazitaet-Western-Digital-Gigantische-Speicherdichte-1445257/</ref>''
* 25.08.2025: Unter dem Begriff "Gayfemboy" operiert ein wieder schädlicheres Botnet, das auf Mirai basiert.<ref>https://www.scworld.com/brief/gayfemboy-botnet-evolution-fortinet-researchers-unveil-advanced-cyber-threat</ref>
* 04.10.2025: Bei Discord ist ein von Datenschützern befürchteter Sicherheitsrisiko eingetreten. Nachdem für manche Onlineanwendungen ein Nachweis mit persönlichen Daten notwendig ist, gibt es bei Discord einen "data breach".
<ref>https://www.theverge.com/news/792032/discord-customer-service-data-breach-hack</ref>
* 18.11.2025: Einer der größten Datenleaks betrifft bei WhatsApp registrierte Telefonnummern bei mehr als 3,5 Mrd. Accounts.<ref>https://www.heise.de/en/news/3-5-Billion-Accounts-Complete-WhatsApp-Directory-Retrieved-and-Evaluated-11083244.html</ref>
* 01.12.2025: Die UC Santa Barbara hat ein Forschungsergebnis präsentiert, das Potential von P-Computern verspricht.<ref>https://news.ucsb.edu/2025/022239/new-ucsb-research-shows-p-computers-can-solve-spin-glass-problems-faster-quantum</ref>
* 17.12.2025: Das CERN verkündet, über 1 Exabyte (1.000.000 Terabyte) an experimentellen Daten vom LHC gespeichert zu haben.<ref>https://home.cern/news/news/computing/cern-hits-one-exabyte-stored-experimental-data-lhc</ref>
<gallery>
NASA LGBT parade.jpg|Unter Trump sollen queere Inhalte zensiert werden. Unter die Anordnung können aber auch Inhalte fallen, die Frauen positiv hervorheben.
CHE TITANO, MSI SVELA LE RTX 50 CUSTOM! 🔥 (1920p 25fps VP9 LQ-152kbit Opus)-00.07.45.534.png|Die RTX 5090 soll in Deutschland mindestens 2.329 € kosten
DeepSeek logo.svg|DeepSeek wird als Konkurrent zu ChatGPT gesehen. Kritik an der VR China wird jedoch ausgeblendet.
FemboyPup.jpg|Ein "Femboy" aus der queeren Szene ist meist ein Begriff für einen Twink mit femininen Elementen
UCSB University Center and Storke Tower.jpg|Neben Binärrechnern und Quantencomputern könnten probabilistische Computer an Relevanz gewinnen
</gallery>
== 2026==
* Die RAM-Preise schießen aufgrund der großen Nachfrage durch KI-Anwendungen in die Höhe.
* 05.06.2026: Cloudflare berichtet, dass der Online-Verkehr durch AI-Agenten und Bots größer als der von Menschen geworden ist. So sollen um diesen Zeitraum etwa 57 % von Bots stammen, und etwa 43 % direkt durch Menschen. Dies könnte die Theorie des "toten Internets" stärken.<ref>https://www.nbcnews.com/tech/tech-news/bot-web-traffic-overtaken-human-web-traffic-data-shows-rcna348522</ref>
* 17.06.2026: Cybernews veröffentlicht einen Bericht über den Leak von 24 Mrd. Datensätzen. Es wird darauf hingewiesen, dass es immer gängiger geworden ist, dass häufiger größere Datensätze mit personenbezogenen Daten öffentlich werden. Man spricht von über 8,3 TB an Daten aus 36 Quellen. Die Datenbank soll jedoch nicht mehr öffentloch auffindbar sein. Grundsätzlich wird empfohlen, Passwörter zu ändern, 2FA zu aktivieren und auf Phishing-Mails zu verzichten.<ref>https://cybernews.com/security/24-billion-credentials-data-leak/</ref>
* 01.07.2026: Sony kündigt an, ab 2028 keine physischen Spiele-Datenträger mehr für die PlayStation anzubieten. Spieler sind erzürnt, da dies das physische Eigentum an Spielen erschwere. Fans fordern ein Umdenken.<ref>https://www.ifun.de/playstation-ohne-scheiben-sony-plant-die-digitale-zukunft-282869/</ref>
* 05.07.2026: Die Internationale Computerspielesammlung aus Deutschland kündigt an, ihre 60.000 Exemplare umfassende Sammlung nicht weiter als Archiv zu führen. Dies ist ein weiterer Rückschlag für die Bewahrung digitaler Inhalte.<ref>https://www.tomshardware.com/video-games/retro-gaming/germanys-1-5-million-project-to-build-the-worlds-largest-game-archive-collapses-after-funding-dries-up</ref>
* 22.07.2026: Ein KI-Agent soll während einer Testung von OpenAI eigenständig in ein Computersystem von Hugging Face eingedrungen sein. Eigentlich sollte das KI-System in einer Sandbox agieren, die abgeschottet ist.<ref>https://www.tagesschau.de/wirtschaft/unternehmen/openai-ki-hackerangriff-100.html</ref>
* Juli 2026: Die Abneigung gegen Smartglasses wird größer. Grund ist unter anderem die niedrigschwellige Möglichkeit, heimlich Video- und Tonaufnahmen von Mitmenschen anzufertigen. Da die Brille auch an bedenklichen Orten wie privaten Orten, Toiletten, Freibädern und gar bei intimen Aktivitäten mitfilmen kann, wird eine gesellschaftliche Debatte zu dieser Technologie vonnöten sein.<ref>https://www.youtube.com/watch?v=1xzZoZ1_zZI</ref>
* Juli: Es wird bekannt, dass KI-Konzerne massenhaft Bücher kaufen, sie in KI-System verarbeiten und die physischen Bücher anschließend vernichten. Kritiker sehen damit eine massenhafte Vernichtung von menschlichem Wissen und Kultur. Aus den Büchern extrahierte Informationen bleiben dafür den KI-Konzernen vorbehalten.<ref>https://futurism.com/artificial-intelligence/ai-companies-destroying-rare-books</ref>
* 09.09.2026: Ein ehemaliger Anthropic-Mitarbeiter spricht über die weitreichenden Gefahren von KI-Modellen in den nächsten Jahren, die die Kontrolle über das Webgeschehen übernehmen könnten. Die Warnung fällt mit dem Release von GPT-6 zeitlich zusammen.<ref>https://www.zdfheute.de/wirtschaft/unternehmen/anthropic-ki-gefahren-mitarbeiter-kritik-100.html</ref>
<gallery>
Micron MTC40F204681RC48BA1R 20240407 076.jpg|Dieses Produkt konnte für 250 € erworben werden, und kostet zeitweise über 1500 €
PS4 games.jpg|Physische Speichermedien überleben Accountlöschungen und Shutdowns von Webdiensten
Ray-Ban Stories.jpg|Eine Klamera links und rechts neben dem Glas kann Gesehenes aufzeichnen; eine Status-LED kann ausgeschaltet werden
</gallery>
===2030===
* 100-TB-HDDs sollen für die Endkundschaft verfügbar sein.<ref>https://www.hardwareluxx.de/index.php/news/hardware/festplatten/55677-ab-2030-seagate-kuendigt-100-tb-hdds-an.html</ref>
</font>
===2035===
* Chinesische Wissenschaftler prophezeien die ersten Zettascale-Exacomputer. Mit Zetta- und Yottascale-Supercomputern soll man menschliche Gehirne akkurat modellieren können.
* Durch mehr Datenaustausch und bessere Interkonnektivität werden Cloudcomputer und Cloudbetriebssysteme immer üblicher. Hierbei werden Dateien in der Cloud gespeichert, und die (meiste) Hardware in der Cloud bzw. als Remote-System zur Verfügung steht. Man kann sich auch Leistung einkaufen oder "mieten".
===2038===
* 19.01.2038: Das Jahr-2038-Problem kann auftreten. Ursache ist die Unixzeit in 32 Bit. Nach 2³² Sekunden ab 01.01.1970 kann ein Überlauf der Bit-Ganzzahl passieren und auf das falsche Datum zurückfallen. 2<sup>64</sup> Sekunden entsprächen knapp 18,5 Trillion Sekunden, was ca. 584,6 Mrd. Jahre wären.
<gallery>
Year 2038 problem.gif|Ablauf des Jahr-2038-Problems
</gallery>
===2050===
* Ein Sachverständiger für digitale Infrastruktur geht davon aus, dass Deutschland in 2050 einen Glasfaservollausbau erreicht haben wird
* Zur Mitte des Jahrhunderts könnte ein "Zeitalter der Vorstellungskraft" eintreten. Hierbei wird die zur Verfügung stehende Rechenleistung genutzt, um ein nie gekanntes Potenzial von Kreativität freizusetzen. Es beginnt eine Abkopplung zur Realität. Ein Eintauchen in andere Welten kann als Ausprägung des Eskapismis gesehen werden. Die Welt ist für viele eine psychische Zumutung, die durch Entfliehen in andere Welten gelindert werden kann.
===2065===
* Papier wird als analoger Datenträger nicht mehr benutzt
==Einzelnachweise==
<references/>
2ktyml31i9pb547nupr68i5kzrxexwx
Gitarre: Lerne CAGED-Stammtöne
0
117512
1090632
1090595
2026-09-09T19:35:56Z
Mjchael
2222
/* Ein Vogel wollte Hochzeit machen */
1090632
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn der Ton C auf ein E-folgt, kann man entweder ein
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
ltfe8oorg1pduqazl7mxfyn1v0ukaqq
1090633
1090632
2026-09-09T19:40:12Z
Mjchael
2222
/* Halbtaktige Sequenzen */ h4
1090633
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn der Ton C auf ein E-folgt, kann man entweder ein
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
i1bmcd1uq5m052xvzmtineos8imwy5d
1090634
1090633
2026-09-09T19:45:33Z
Mjchael
2222
/* Eintaktige Sequenzen */
1090634
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn der Ton C auf ein E-folgt, kann man entweder ein
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
k1uro9c6oquzat8s49ns4i0vsmfxsz3
1090635
1090634
2026-09-09T19:51:40Z
Mjchael
2222
/* Zweiter Fingersatz */ verschieben
1090635
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn der Ton C auf ein E-folgt, kann man entweder ein
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
isgxyzm426cll5n2ez0qup244iemud9
1090636
1090635
2026-09-09T19:57:26Z
Mjchael
2222
Version 1090635 von [[Spezial:Contributions/Mjchael|Mjchael]] ([[Benutzer Diskussion:Mjchael]]) wurde entfernt. Probleme beim Verschieben
1090636
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn der Ton C auf ein E-folgt, kann man entweder ein
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
k1uro9c6oquzat8s49ns4i0vsmfxsz3
1090639
1090636
2026-09-10T04:21:39Z
Mjchael
2222
/* Töne der C-Dur Tonleiter auf dem Griffbrett */
1090639
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen.
Wir bevorzugen die englischen Notennamen, da diese in der Molltonleiter den Alphabet folgen.
;A BC • D EF
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn der Ton C auf ein E-folgt, kann man entweder ein
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
as78v54bjnko4dahv2i293mt034n2iz
1090640
1090639
2026-09-10T04:47:38Z
Mjchael
2222
/* G-Form • Ein Vogel */
1090640
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen.
Wir bevorzugen die englischen Notennamen, da diese in der Molltonleiter den Alphabet folgen.
;A BC • D EF
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier ist es wohl am einfachsten, dass du den kleinen Finger umlegst, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn zwei Töne im selben Bund sind, kann man entweder einen Minibarré spielen, oder ein Finger muss vorübergehend seine bevorzuge Position verlassen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
3h2t2u5445773ogxgoci1sji3467yex
1090642
1090640
2026-09-10T04:52:53Z
Mjchael
2222
/* A- (Bb-)Form • Ein Vogel */
1090642
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen.
Wir bevorzugen die englischen Notennamen, da diese in der Molltonleiter den Alphabet folgen.
;A BC • D EF
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier kannst du auch versuchen, den kleinen Finger umzulegen, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn zwei Töne im selben Bund sind, kann man entweder einen Minibarré spielen, oder ein Finger muss vorübergehend seine bevorzuge Position verlassen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
ltkulkqmujz5odlqi5qlvokma88ls15
1090643
1090642
2026-09-10T05:20:37Z
Mjchael
2222
/* C-Form • Ein Vogel */ Oktave
1090643
wikitext
text/x-wiki
{{:Gitarre/ Navi|Sologitarre|
{{:Gitarre: Sologitarre/ Navi Improvisation in Dur und Moll}}|
img=Guitar 1.svg |bg=#F8f8f8|border=darkorange|color=dark|px=80|navi=Einführung in die Sologitarre}}
= Wiederholung der Fingersätze =
; mit Schwerpunkt auf den Stammtönen
Diese Wiederholung ist zum einen dafür gedacht, die vorhergehenden Übungen auf jeder Saitenlage zu machen, und auch in jeder Bundlage, gleichgültig ob die Finger eng beieinander oder weit auseinander stehen. Zum andern sind diese als Vorbereitung in die Sologitarre gedacht. Beispielsweise als Auflockerungsübung zwischen den Barré-Akkorden. Besonderen Augenmerk wollen wir hier auf die Notennamen legen. Diese können hier mitgelernt werden.
Solltest du meinen, das sei noch nicht für dich dran und kann warten, dann springe zur ersten CAGED-Skala. Du kannst beim Kapitel Longform nochmal hierrauf zurückkommen.
* [[Gitarre: CAGED-Skala D-Dur-Form|CAGED-Skala D-Dur-Form]]
Lassen wir die [[Gitarre: Aufbau der CAGED-Skalenformen|erste Lektion]] (insbesondere für die Quereinsteiger) noch einmal Revue passieren.
Die folgenden Übungen enthalten oft eine Folge von ein- oder zweitaktigen Sequenzen. Eine Sequenz ist ein Motiv, dass sich auf verschiedenen Tonhöhen wiederholt.
Auch ohne Notenkenntnisse kannst du den Verlauf und die Wiederholungen der Sequenzen einfacher im Notenbild verfolgen, als in der Tabulatur; insbesondere wenn du dir gleichzeitig die Übung anhörst. Es kommen auch Ausschnitte aus klassischen Stücken, Folksongs, Kinderlieder o.ä. vor. Die einfache Struktur oder der Bekanntheitsgrad der Melodien sollen dir das Üben erleichtern. Die Finger finden so leichter ihre Position, als wenn du erstmal jede einzelne Note aus der Tabulatur entschlüsseln musst.
Jede Übung wird auf allen Saitenlagen geübt. Vorher blieben wir in den mittleren Lagen. Jetzt gehen wir auch in die ersten Bünde, wo man die Finger etwas mehr spreizen muss, und in die höheren Lagen, wo es ein wenig eng wird. Die Stücke wiederholen sich in dieser Lektion in der selben Tonart, doch auf verschiedenen Bünden. Du spielst immer die selbe Tonfolge, nur auf verschiedenen Tonhöhen bzw. auf verschiedenen Saitenlagen. Lediglich zwischen der G- und H-Saite musst du dir jedesmal überlegen, wie sich der Lagewechsel auf den Fingersatz auswirkt. Doch der Fingersatz in den anderen höheren Lagen bleibt immer gleich. Wie die Tonfolgen mit dem CAGED-System zusammenhängen, das muss dich nur am Rande interessieren. Es wird in den folgenden Lektionen näher und ausführlicher erleutert.
:[[Datei:Scala Griffbrett.svg]]
Wir hatten uns bei den vorhergehenden Übungen weitestgehend an den Intervallen (1-j7) und an der Tabulatur orientiert. Diese sind in allen Tonarten gleich.
Suche zuerst das Karré!
Daran orientierst du dich.
:[[Image:Scala Carree.svg]]
{{Tipp|Lerne bei der C-Dur-Tonleiter nicht nur die Intervalle <br>
2 - 3 4 - 5<br>
6 - j7 1 - 2<br>
sondern benenne auch jede einzelne Note. <br>
D - E F - G<br>
A - H C - D<br>
So bekommst du einen recht einfachen Überblick über das Griffbrett.}}
== Töne der C-Dur Tonleiter auf dem Griffbrett ==
Wir wollen uns in dieser Lektion auf die Töne bzw. die Notennamen konzentrieren. Allerdings sparen wir uns vorerst alle Töne mit Vorzeichen aus. Die [[Gitarre: Aufbau der CAGED-Skalenformen|ersten Übungen zum 1. und 2. Fingersatz]] werden auf die Tonart C-Dur bzw. A-Moll übertragen und wir spiele sie in den hier gezeigten Positionen.
Wir fangen mit dem zweiten Fingersatz an, wo wir entweder den Ton C oder den Ton A der C-Dur- bzw. Am-Tonleiter als Orientierung nutzen.
Wir bevorzugen die englischen Notennamen, da diese in der Molltonleiter den Alphabet folgen.
;A BC • D EF
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Du hast vermutlich allerlei Akkordformen des CAGED-System gesehen.
<div class="noprint">
;Animation
[[Image:Crd Grundtonschema ani.gif]]
</div>
<score>
<<
\new ChordNames { \chordmode {
c1 c c c c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c'-1\4 g'-2\3 c''-4\2 e''-3\1 >
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Wenn du schon Fingerstyle oder Jazz spielst, mögen dir viele der Formen bekannt vorkommen. Doch selbst wenn du bis jetzt nur das [[Gitarre: Rockdiplom|Rockdiplom]] gemacht hast und mit den dort vorkommenden Barré-Akkorden vertraut bist, wirst du sehen, dass die einfachen Barré-Akkorde ausreichen, um sich auf dem Griffbrett zu zurechtzufinden.
Die [[Gitarre: C-Dur-Tonleiter Workshop|C-Dur-Tonleiter in den ersten drei Bünden]] setze ich als bekannt voraus und es sollte dir nicht allzu schwer fallen, diese in den 12. Bund zu übertragen.
:[[Datei:Scala C-Am.svg|150px]][[Datei:C-Dur_Majorpattern_III.jpg|150px]]
C-Dur als Barré im 3. Bund kennst du vom Rockdiplom, und C-Dur im 8. Bund ist auch kein Hexenwerk. Dazwischen liegt nach dem CAGED-System die G-Form, die dir vermutlich noch nicht untergekommen ist (hier mit weißem Fingersatz). Statt uns die Töne von der G-Form abzuleiten, machen wir es uns einfacher und leiten uns die Töne zur Orientierung vom Am im 5. Bund ab. Du erinnerst dich noch an die Dur- und Mollparallelen? (C- \ Am-Tonleiter bzw. G- \ Em-Form). Oder du nutzt die Grundtöne des C-Barré im 8. Bund.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a:m c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 e-2 g c'-1 e' >
< c-1\5 g-3\4 c'-3\3 e'-4\2 g'-1 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 e-2\5 g-1\4 c'-1\3 e'-1\2 c''-4\1>
< a,-1\6 e-3\5 a-4\4 c'-1\3 e'-1\2 a'-1\1 >
< c-1\6 g-2\5 c'-3\4 e'-4\3 g'-1\2 c''-1\1>
< c'-4\5 e'-3\4 g'-1\3 c''-2\2 e''-1\1 >
}
>>
</score>
Leite dir also die Grundtöne C und A von den dir bekannten Barré-Akkorden ab und spare dir die ungewöhnlicheren Akkordformen auf, bis sie dir später beim Fingerstyle oder Jazz begegnen. Es macht dabei garnichts aus, wenn du zum Auffinden der Grundtöne und zum Finden des Starttons ein paar Sekunden brauchst. Du wirst sehen, dass die Wiederholungen der bekannten Übungen auf den verschiedenen Bünden und in verschiedenen Oktavebereichen leicht von der Hand gehen. Lediglich beim Lagewechsel zwischen der G- und H-Saite musst du etwas überlegen.
<score>
<<
\new ChordNames { \chordmode {
c1 c c a c c
}}
\new FretBoards {
% \override FretBoards.FretBoard.size = #'1.5
\override FretBoard.fret-diagram-details.finger-code = #'in-dot
% \override FretBoard.fret-diagram-details.dot-color = #'white
\override FretBoard.fret-diagram-details.orientation =
#'landscape
< c-3 c'-1 >
< c-1\5 c'-3\3 >
\once \override FretBoard.fret-diagram-details.dot-color = #'white
< c-3\6 c'-1\3 c''-4\1>
< a,-1\6 a-4\4 a'-1\1 >
< c-1\6 c'-3\4 c''-1\1>
< c'-4\5 c''-2\2 >
}
>>
</score>
Diese wenigen"Eckpunkte" reichen aus, um dich grob auf dem Griffbrett zurechtzufinden. Suche sie noch einmal in der Skala und natürlich auch auf deinem Griffbrett.
:[[Datei:C-Major-Scale on the fretboard.svg]]
== Zweiter Fingersatz ==
:[[Datei:Scala 6_71-2_34.svg]]
Zuerst suchen wir uns in der C-Dur-Tonleiter überall den zweiten Fingersatz heraus.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
Zur leichteren Orientierung wird die Grafik bei jeder neuen Melodie wiederholt.
=== Rondeau (Auszug) ===
Die eintaktige Sequenzen wurde aus einem Rondeau von J.S. Bach entnommen, dass beliebig wiederholt werden kann. Der Grundton C, welcher im letzten Takt rot eingefärbt wurde, wird mit dem kleinen Finger gegriffen.
Du kannst tatsächlich die Noten nutzen (sofern du es schon kannst) oder aber du orientierst dich an den Notennamen.
Am Anfang des Griffbrettes brauchen wir den zweiten Fingersatz nicht vollständig.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
In der A-(Bb-)Form müssen wir den Lagewechsel zwischen der G- und H-Saite beachten. Übrigens werden hier die Töne in der englischen Form angegeben. (Bb-Form und der Ton B statt des deutschen H.) Nur der erste Bund wird bis zur letzten Note in der dritten Lage gespielt. Der Rest bis zur letzten Note in der zweiten Lage.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (A-, Bb-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e-4
d-2 c d e d c b d
c b c d c b a c
b a b c d b c d-1
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt in der G-Form das C zu suchen, suche lieber das A im 5. Bund (hier grün hervorgehoben). Oder du leitest dir das C vom Barré im 8. Bund ab. Der Startton E ist auf der A Saite im 7. Bund unter dem Ringfinger. Ansonsten stellt der Fingersatz keine Herausforderung mehr dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (G-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b \once \override NoteHead #'color = #green a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der kleine Finger des C-Barré im 8. Bund in der E- bzw. F-Form gibt gleichzeitig das C des zweiten Fingersatz an. Du siehst, dass ab jetzt alles leichter geworden ist, weil sich ansonsten nichts mehr am Fingersatz ändert.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- F-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Für den Grundton C müssen wir uns die D-Form gar nicht so genau ins Gedächtnis rufen, wenn uns die C-Form viel vertrauter ist.
Diese hohe Lage ist für E-Gitarristen oder Gitarren mit Cutaway gedacht. Auf der Konzertgitarre ist die sehr hohe Lage schlecht zu spielen. Gehe ggf. einen Kompromiss ein, und spiele diese hohe Saitenlage ein paar Bünde tiefer als Übung nur für den Fingersatz aber nicht für die Notennamen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Noten über dem hohen C (der mit zwei Hilfslinien) wird dir seltener begegnen, da in dem Fall bevorzugt die Noten nach unten oktaviert werden. (Beachte die 8 im Notensystem.) Bei den weiteren Übungen werden jedoch die Versionen mit den vielen Hilfslinien angezeigt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
\ottava #1 e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Mit der C-Form in den ersten drei Bünden im Hinterkopf ist der 12. Bund leicht zu bewältigen. Wieder eine Übung, die weniger für Konzertgitarren geeignet ist.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in C-Dur"
subtitle="Rondeau (Auszug)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
\repeat volta 2 {
e8-2 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
}
\once \override NoteHead #'color = #red c1^\markup { \bold {(C)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 d e f e d c e
d c d e d c b d
c b c d c b a c
b a b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== "Das häßliche Entlein" oder "Alle meine Entchen"<ref>Anspielung auf ein Märchen der Gebrüder Grimm nebst einem bekannten deutschen Kinderlied.</ref> in A-Moll ===
Die vorherige Übung war in Dur, und hier verwenden wir ein und den selben Fingersatz in Moll. Wie du siehst und hörst, lässt sich ein Fingersatz oder ein Pattern nicht eindeutig einer einzigen Tonart zuordnen. Der Schlusston oder der Schlussakkord (hier der Ton A bzw. der Akkord Am) bestimmt die Tonart. Der Grundton A ist hier die Sexte (6) des zugrunde liegenden C-Major-Pattern. Es bleibt dir überlassen, ob du zur Orientierung lieber den Grundton A (grün) bestimmst, oder das C aus dem Karré (rot).
Wenn in einer Tabulatur über einer Ziffer zwei Notenhälse stehen, so ist das ein Zeichen für eine halbe Note, die zwei Schläge dauert. Da dieses für viele Gitarristen sehr ungewöhnlich aussieht, verzichtet man oft auf Taktstriche in der Tabulatur. In dem Fall lässt sich die Tondauer allein an den Notenwerten ablesen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-/Am-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #5
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Der Lagewechsel zwischen der G- und H-Saite ist hier leicht zu bewältigen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Gm-/Bb-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d-1 e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2-4 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier ist es wieder einfacher das A (grün) zu suchen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-/G-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (E- / F-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Statt lange nach dem Grundton der D-Form zu suchen, erinneren wir uns kurz, wo der Grundton C auf der H- (B-)Saite sein muß (13. Bund).
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C-Form) in Am"
subtitle="Das häßliche Entlein"
subsubtitle="oder: Alle meine Entchen in Moll"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4-1 b
\once \override NoteHead #'color = #red
c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b c d e2 e f4 f f f e1
f4 f f f e1 d4 d d d c2 c
b4 b b b a1
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Die Moldau (Hauptmotiv) ===
Die Abfolge der Töne der folgenden Übung unterscheidet sich kaum von der vorhergehenden. Doch mit dem anderen Rhythmus haben wir das Hauptmotiv von der Komposition {{Youtube-Suche|Smetana+Die+Moldau|"Die Moldau" von Bedrich Smetana}} (ohne Auftakt und rhythmisch vereinfacht).
Auch wenn es hier (wie in der 7. Übung) nur die Molltonleiter rauf und runter geht, merkst du hoffentlich, wieviel der Takt und Rhythmus an der Wirkung ausmacht. Wenn du später mal meinst, deine Improvisationen hören sich langweilig an, dann solltest du dich mehr mit Rhythmus beschäftigen. Dazu kannst du dich auch ein wenig mit Schlagmustern beschäftigen.
:[[Datei:C-Major-Scale_on_the_fretboard_second_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Warum die Form hier Gm-Form genannt wird, das wird dir in den nachfolgenden Lektionen klarer werden. Auf Fingersatzangaben können wir hier verzichten, wenn du vorher "Alle meine Entchen in Am" gespielt hast.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Bb- /Gm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier bietet sich besonders an, den Am-Barré zur Orientierung zu verwenden.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (Em-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #5
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Auch hier gibt dir der kleine Finger des Am-Barrés den Grundton an. Du kannst dir die Dm-Form aber auch über die F-Form (C im 8. Bund) ableiten.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (F- /Dm-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Zähle vom C (H-Saite, 13. Bund) rückwärts zum A.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (D- /Bm7-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier wird die erste Übung in den 12. Bund verschoben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="2. Fingersatz (C- /Am-Form) in Am"
subtitle="Die Moldau (Hauptmotiv)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key a \minor
\once \override NoteHead #'color = #green
a4 b8
\once \override NoteHead #'color = #red
c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 6/8
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
a4 b8 c4 d8 e4. e4. f4. f4. e2.
d4. d4. c4 d8 c4. b4. b4. a2.
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==1. Fingersatz==
Dir wird wohl aufgefallen sein, dass beim zweiten Fingersatz der Ton G fehlt. Den üben wir mit dem ersten Fingersatz.
:[[Datei:Scala 71_2-34_5.svg]]
Beachte, dass der Grundton (1) unter dem Ringfinger (also im zweiten Bund dieses Fingersatzes) ist, und dass du deine freie Improvisationsübung in Dur günstigerweise mit der (1) beginnen oder zumindest enden sollte.
Diesen Fingersatz suchen wir in der C-Dur-Tonleiter auf dem Griffbrett.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
=== Eintaktige Sequenzen ===
Du wirst feststellen, dass sich die Sequenzen recht schnell lernen lassen.
==== 1. Fingersatz • C-Form (open) ====
Die erste Lage mit leeren Saiten stellt noch keine Herausforderung dar.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • A- (Bb-)Form ====
Du musst noch nicht einmal den C-Barré im 3. Bund bemühen, um den Grundton zu finden. Die C-Dur-Tonleiter in den ersten drei Bünden reicht. Natürlich kannst du auch den Startton G suchen. Die Tabulatur sagt dir "D-Saite 5. Bund". Erinnere dich daran, dass dies der Stimmton der D-Saite ist (beim Stimmen nach Bünden). Auch hier ist der Fingersatz leicht.
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 3.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 3 darkgrey )
(place-fret 4 3 4 yellow3 )
(place-fret 4 5 5 darkgrey )
(place-fret 5 2 "j7" yellow3 )
(place-fret 5 3 1 black )
(place-fret 5 5 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • G-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 3 darkgrey )
(place-fret 2 6 4 yellow3 )
(place-fret 2 8 5 darkgrey )
(place-fret 3 4 "j7" yellow3 )
(place-fret 3 5 1 black )
(place-fret 3 7 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
Beachte den Lagewechsel zwischen der G- und H-Saite. Den Grundton C kannst du dir auch vom Ringfinger auf der G-Saite des C-Barrés ableiten.
Du musst dir hier eine Strategie zurechtlegen, wann du den Lagewechsel durchführen möchtest. Ich empfehle hier, den Lagewechsel so früh wie möglich zu machen, damit du den Zeigefinger frei hast, um gleich hintereinander zwei Töne in einem Bund zu spielen. Betrachte die Angaben zum Fingersatz nur als Vorschlag.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d-4 e-2 f-3 d e f
e d c d e c-1 d-4 e-2
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Hier eine alternative Lösung. Du kannst einen kleinen Barré über die Noten C und E legen, und den Lagewechsel später ausführen. Das V unter dem C zeigt hier den 5. Bund an, und nicht etwa Abschläge. Der Lagewechsel erfolgt hier im letzten Takt.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8-4 f e f g e f g
f e d e f d e f
e d-2
\textSpannerDown
\override TextSpanner.bound-details.left.text = "V"
c-1\startTextSpan
d e-1 c-1 d e-1\stopTextSpan
d-4 c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • E- (F-)Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 3 darkgrey )
(place-fret 5 8 4 yellow3 )
(place-fret 5 10 5 darkgrey )
(place-fret 6 7 "j7" yellow3 )
(place-fret 6 8 1 black )
(place-fret 6 10 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Den Grundton C auf der E-Saite kannst du dir vom C-Barré der E-Form (wie ein F- Barré) im 8. Bund ableiten. Der Fingersatz ist wieder einfach.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F)-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 1. Fingersatz • D-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 3 darkgrey )
(place-fret 3 10 4 yellow3 )
(place-fret 3 12 5 darkgrey )
(place-fret 4 9 "j7" yellow3 )
(place-fret 4 10 1 black )
(place-fret 4 12 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Die Tonhöhe ist die selbe, wie in der G-Form, wo wir uns komplizierte Strategien für den Fingersatz zurechtlegen mussten. In dieser Lage ist alles einfacher. Wenn du später mal einen herausfordernden Lick zwischen der G- und H-Saite hast, wäre eine weitere gangbare Strategie den Lick in eine fingertechnisch günstigere Lage zu verlegen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== 1. Fingersatz • C-Form ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 3 darkgrey )
(place-fret 1 13 4 yellow3 )
(place-fret 1 15 5 darkgrey )
(place-fret 2 12 "j7" yellow3 )
(place-fret 2 13 1 black )
(place-fret 2 15 2 darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Hier wurde die C-Durtonleiter in den 12. Bund verlegt. Der Grundton ist auf der H-Saite im 13. Bund. (Eine Oktave höher als bei der C-Dur Tonleiter in den ersten drei Bünden.) Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Eintaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
\once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 f e f g e f g
f e d e f d e f
e d c d e c d e
d c b c d b c d
c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen ===
Diesmal hast du halbtaktige Sequenzen, die einmal wiederholt werden.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • 1. Fingersatz ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==== A- (Bb-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • A- (Bb-)Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 4 2 "E" darkgrey )
(place-fret 4 3 "F" yellow3 )
(place-fret 4 5 "G" darkgrey )
(place-fret 5 2 "B" yellow3 )
(place-fret 5 3 "C" black )
(place-fret 5 5 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Leite dir den Grundton vom C-Dur-Akkord, oder vom C-Barré im 3. Bund ab. Lerne nicht nur die Intervlle, sondern auch die Notennamen. (Zumindest bei den einfachen Tonarten F-, G- und C-Dur). Andere Tonarten kommen später dran.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- / Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • G-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 2 5 "E" darkgrey )
(place-fret 2 6 "F" yellow3 )
(place-fret 2 8 "G" darkgrey )
(place-fret 3 4 "B" yellow3 )
(place-fret 3 5 "C" black )
(place-fret 3 7 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>Du kannst die beiden hintereinander folgenden Noten im 5. Bund mit einem Mini-Barré ausführen, und die Lagewechsel mittels Slide (= Glissando) durchführen, oder wie in der Wiederholung ohne Slide durchführen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8-1 g' f e d f e d
c-1 e-1 d c-1(\glissando b-1) d c b-1(\glissando c1-1)
c8-2 g' f e d f e d
c-1 e-2 d-4 c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • E- (F-)Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 5 7 "E" darkgrey )
(place-fret 5 8 "F" yellow3 )
(place-fret 5 10 "G" darkgrey )
(place-fret 6 7 "B" yellow3 )
(place-fret 6 8 "C" black )
(place-fret 6 10 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Fingersatztechnisch wieder problemlos.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • D-Form
<score raw="1">
\version "2.14.2"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 3 9 "E" darkgrey )
(place-fret 3 10 "F" yellow3 )
(place-fret 3 12 "G" darkgrey )
(place-fret 4 9 "B" yellow3 )
(place-fret 4 10 "C" black )
(place-fret 4 12 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
Wieder klingt diese Lage genau so, wie die G-Form, ist aber vom Fingersatz her einfacher.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • 1. Fingersatz ====
<div style="float:left; padding:5px;margin:5px; border:black solid 1px; ">
;1. Fingersatz • C-Form
<score raw="1">
\version "2.24.4"
\markup {
\override #'(size . 4.0) {
\override #'(fret-diagram-details . (
(orientation . landscape )
(finger-code . in-dot )
(dot-color . #'black)
(dot-radius . 0.4)
(dot-position . 0.5)
(top-fret-thickness . 6)
(fret-count . 3)
(number-type . roman-upper)
))
\fret-diagram-verbose #'(
(place-fret 1 12 "E" darkgrey )
(place-fret 1 13 "F" yellow3 )
(place-fret 1 15 "G" darkgrey )
(place-fret 2 12 "B" yellow3 )
(place-fret 2 13 "C" black )
(place-fret 2 15 "D" darkgreen )
)
}}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div> Die H-Saite heißt auch im 12. Bund H, also ist im 13. Bund das C. Wer keine E-Gitarre hat oder wer keine Akkustik mit Cutaway hat, der kann die C-Form auch in einem niedrigeren Bund üben.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b \once \override NoteHead #'color = #red c1
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 g' f e d f e d
c e d c b d c b c1
c8 g' f e d f e d
c e d c b d c b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
=== Ein Vogel wollte Hochzeit machen ===
Hier habe ich ein relativ bekanntes Kinderlied gefunden, dass perfekt zum 1. Fingersatz passt. Die Tondauern sind für Ungeübte in Sachen Noten schwer herauszulesen. Kennst du aber das Stück, oder hörst du es dir mehrmals an, so ist es keine unüberwindbare Schwierigkeit.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
==== C-Form (open) • Ein Vogel ====
Folgt das G nach dem D, greifst du den besser mit dem kleinen Finger.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8 d d-3 g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== A- (Bb-)Form • Ein Vogel ====
Hier kannst du auch versuchen, den kleinen Finger umzulegen, wenn du nach dem D den G greifen willst.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d-3( g-4) g g16 e |
c8 8 8 g'16 e d8-3 d d g16-4 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== G-Form • Ein Vogel ====
Wenn zwei Töne im selben Bund sind, kann man entweder einen Minibarré spielen, oder ein Finger muss vorübergehend seine bevorzuge Position verlassen.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e-2 c-1 g' e d( g) g g16 e-2 |
c8-1 8 8 g'16 e d8 d d g16 f |
e8-2 c-1 d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== E- (F-)Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== D-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== C-Form • Ein Vogel ====
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Ein Vogel wollte Hochzeit machen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
r2. r8 e8 |
g8 e g e f d f d |
e c g' e d( g) g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b \once \override NoteHead #'color = #red c4 r4
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
e8 |
g8 e g e f d f d |
e c g' e d_g g g16 e |
c8 8 8 g'16 e d8 d d g16 f |
e8 c d b c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Halbtaktige Sequenzen (2) ===
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A- (Bb-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
Bei der G-Form kommt es zwischen der G- und H-Saite zu einem Lagewechsel. Du musst dir jedesmal eine Strategie zurechtlegen, wann und wie du am besten den Lagewechsel durchführst.
Wenn du Glück hast, findest du im Notenbild einen Hinweis, wie man günstig die Lage wechseln kann. Ich empfehle dir dort wo die 2 über den Noten steht, den Mittelfinger zu nehmen.
*(1 = Z, 2 = M, 3 = R, 4 = K, 0 = leere Saite)
Betrachte solche Hinweis nur als Vorschlag, denn es gibt keine verbindliche Regel, wie der Lagewechsel zu erfolgen hat. Übst du die gleiche Sequenzen ein paar Saiten höher oder tiefer, geht es leichter von der Hand.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E- (F-)Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Halbtaktige Sequenzen (2)"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c''' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
g8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1
g'8 e f g f d e f
e c-2 d e d b c d \once \override NoteHead #'color = #red c1^\markup { \bold {(C5)} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
g8 e f g f d e f
e c-2 d e d b c d c
g'8 e f g f d e f
e c-2 d e d b c d c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
=== Einsingen ===
Diese beiden Motive kennen viele, die schon einmal in einem Chor gesungen haben. Leider entsprechen viele Lieder in ihrem Tonumfang nicht genau einem der vollständigen drei Fingersätze oder der später folgenden Skalen. Zumeist werden nur Ausschnitte aus den Patterns gebraucht. Im ersten Motiv fehlt beispielsweise die große Septime (j7) vor dem Grundton.
Dafür enthält das zweite Motiv die große Septime (j7). Das zweite Motiv eicht den Chor auf die gerade geforderte Tonart. Hier werden nur Akkordtöne in einer auf oder absteigenden Tonfolge gespielt (auch Arpeggios genannt). Der A7-Akkord enthält sowohl den Leitton (j7) der zum Grundton (1) hin leitet, als auch den Strebeton (4) die zur Durterz (3) hin strebt. Mit den zwei spannungsreichen Tönen, die sich zum Grundakkord auflösen wollen, wird der Chor auf die Durtonart eingenordet. Hier brauche ich dir nicht zu erklären, wo der Grundton D ist.
:[[Datei:C-Major-Scale_on_the_fretboard_first_fingering.svg]]
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
% \set TabStaff.minimumFret = #2
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (A-(Bb-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (G-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (E-(F-)Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (D-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="1. Fingersatz (C-Form) in C-Dur"
subtitle="Einsingen"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
c8^\markup { \bold {C} } d e f g f e d | c1
c8 d e f g f e d | \once \override NoteHead #'color = #red c1
\break
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b | c1^\markup { \bold {C} }
c4^\markup { \bold {C} } e8 g | f4^\markup { \bold {G7} } d8 b |
\set TabStaff.minimumFret = #0
\once \override NoteHead #'color = #red c1^\markup { \bold {C} }
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant \addlyrics {
c8 d e f g f e d | c1
c8 d e f g f e d c1
\break
c4 e8 g | f4 d8 b | c1
c4 e8 g | f4 d8 b | c
}
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
<br>
==Erste über den zweiten Fingersatz==
Wie du siehst, kommt hier jedesmal zuerst der erste Fingersatz mit dem "Karree" rechts, und dannach kommt der Fingersatz mit dem "Karree" links. Sie sind immer untereinander. Nur zwischen der G- und B-Saite verschiebt sich alles um einen Bund.
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\paper{
indent=0\mm
line-width=120\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:2;f:1;
3-3-2;3-5-3;3-6-4;
4-3-6;4-5-7;4-6-1;
5-3-3;5-4-4;5-6-5;
6-3-7;6-4-1;6-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:2;f:1;
1-4-2;1-6-3;1-7-4;
2-4-6;2-6-2;2-7-1;
3-3-3;3-4-4;3-6-5;
4-3-7;4-4-1;4-6-2;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
=== Jamaica Farewell ===
Die Melodie von [[Liederbuch/ Jamaica Farwell|Jamaica Farwell]] wurde erheblich vereinfacht, damit du dir nicht zu viele Gedanken um den Rhythmus machen musst. Wenn du dich am Quintillo (dem Rhythmus vom Lagerfeuerschlag} orientierst, solltest du wenige Probleme haben. Es gibt recht viele Wiederholung. Die Strophe wurde bei der Wiederholung in die Oktave verschoben, damit das Stück exakt in den Skalenausschnitt passt. Du musst dir für die Fingersätze ggf. Strategien zurechtlegen, damit du die Finger bequem sortiert bekommst.
Das Stück beginnt mit dem Ton G. Der (5) in 1. Fingersatz.
;Bb-Form
Greife den C wie ein Bb-Barré im 3. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-4-2;2-6-3;2-7-4;
3-3-6;3-5-7;3-6-1;
4-3-3;4-4-4;4-6-5;
5-3-7;5-4-1;5-6-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (A-, Bb-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #2
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
; F-Form
Greife den C wie ein F-Barré im 8. Bund. Leite dir von diesem Akkord den Grundton (1) ab, und wandere beim 1. Fingersatz rauf zum Startton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-7-2;3-9-3;3-10-4;
4-7-6;4-9-7;4-10-1;
5-7-3;5-8-4;5-10-5;
6-7-7;6-8-1;6-10-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (E-, F-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
;D-Form
Schiebe den D-Dur-Akkord in den 12. Bund. Ein D im 12. Bund verschoben ergibt ein C. Leite dir von diesem Akkord den Grundton (1) ab. Orientiere dich kurz im 2. Fingersatz und wandere zurück zum ersten Fingersatz zum Ton G (5).
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-10-2;1-12-3;1-13-4;
2-10-6;2-12-7;2-13-1;
3-9-3;3-10-4;3-12-5;
4-9-7;4-10-1;4-12-2;
"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
{{clear}}
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="Jamaica Farewell (vereinfacht)"
subtitle="1. und 2. Fingersatz (D-Form) in C-Dur"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c'' {
\key c \major
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
\repeat volta 2 {
c8 4 e4. 4 | d8 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g'8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8-1~ 2 }
}
\repeat volta 2 {
c'8-3 4 e4.-4 4 | d8-1 e4 f8~2 | }
\alternative {
{ b,8 4 d4. 4 | c8 d4 e8~2 | }
{ e8 4. d4 e8 d | d c4 8~ 2 }
}
\repeat volta 2 {
g8 4 4 8 4 | a8 b4 c c8 b a |
g8 g4 f4 e8 d4 | }
\alternative {
{ e8 f4 g8~ 2 }
{ e8 d4 c8~ 2 }
}
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\tabFullNotation \Diskant
}
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==3. Fingersatz==
Es fällt auf, dass der 3. Fingersatz kein "Karré" hat.
{|
!Fingersatz
!width="30px"|
!Intervalle
|-
|[[Image:Scala Z RK-Z K-ZM K.svg]]
!width="30px"|
|[[Image:Scala 2 34-5 6-71 2.svg]]
|}
Der 3. Fingersatz ist gar kein eigenständiger Fingersatz. Der obere Teil des 3. Fingersatzes ist eigentlich schon der untere Teil des 2. Fingersatzes. Ebenso ist der untere Teil des 3. Fingersatzes gleichzeitig der Anfang des 1. Fingersatzes.
Du musst dir Strategien zurechtlegen, wie du den Übergang vom Ende des 2. Fingersatzes über die 5 und die 6 hin zum 1. Fingersatz gestaltest. Es kommt beim 3. Fingersatz zu einem Lagewechsel nach links.
Übe den 3. Fingersatz zuerst in den obersten Saitenlagen (E A D G x x)
=== Eine II-V-I-Verbindung ===
Wir spielen eine einfache Tonfolge über einer 2-5-1-Verbindung. Die Akkordtöne liegen zumeist auf den schweren Zählzeiten.
* D, F, A, C gehören zum Dm7
* G, B, D, F gehören zum G7
* C, E, G gehören zum C-Dur-Akkord.
Wir nutzen das CAGED-System, um uns grob auf dem Griffbrett zurechtzufinden.
==== Exkurs: Skalenformen ====
Die Namen der Skalen leiten sich übrigens von folgenden einfachen Tonleitern in den ersten Bünden ab:
[[Image:Scala C-Am.svg|100px]] [[Image:Scala Bb-Gm.svg|100px]] [[Image:Scala G-Em.svg|100px]] [[Image:Scala F-Dm.svg|100px]] [[Image:Scala D-Hm.svg|100px]]
Alle Akkorde die man aus diesen einfachen Tonarten kennt, Bassläufe und ähnliches lassen sich zum großen Teil auf die entsprechenden 5 CAGED-Skalen übertragen, fast so als habe man die Tonleiter mittels Kapodaster in eine höhere Lage verschoben.
Wie du siehst, nennen wir die Skalen entgegen des reinen CAGED-System nicht E-Dur-Form (Shape) und nicht die A-Dur-Form (Shape), sondern F- und Bb-Dur-Form.
<div style="float:left; padding:5px; border:black solid 1px; ">
;E-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-1;1-2-2;1-4-3;
2-0-5;2-2-6;2-4-7;
3-1-3;3-2-4;3-4-5;
4-1-7;4-2-1;4-4-2;
5-0-4;5-2-5;5-4-6;
6-0-1;6-2-2;6-4-3;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;F-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-3; 1-1-1; 1-3-2;
2-1-5; 2-3-6;
3-0-2; 3-2-3; 3-3-4;
4-0-6; 4-2-7; 4-3-1;
5-0-3; 5-1-4; 5-3-5;
6-0-7; 6-1-1; 6-3-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;G-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-3; 1-4-1; 1-6-2;
2-4-5; 2-6-6;
3-3-2; 3-5-3; 3-6-4;
4-3-6; 4-5-7; 4-6-1;
5-3-3; 5-4-4; 5-6-5;
6-3-7; 6-4-1; 6-6-2; "
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die G-Dur-Tonleiter von der Form her eher wie die F-Dur-Tonleiter als wie die E-Dur-Tonleiter aussieht.
<div style="float:left; padding:5px; border:black solid 1px; ">
;A-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-0-5;1-2-6;1-4-7;
2-0-2;2-2-3;2-3-4;
3-1-7;3-2-1;3-4-2;
4-0-4;4-2-5;4-4-6;
5-0-1;5-2-2;5-4-3;
6-0-5;6-2-6;6-4-7;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;Bb-Dur-Tonleiter
<br>
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-1-5; 1-3-6;
2-1-2; 2-3-3; 2-4-4;
3-0-6; 3-2-7; 3-3-1;
4-0-3; 4-1-4; 4-3-5;
5-0-7; 5-1-1; 5-3-2;
6-1-5; 6-3-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; border:black solid 1px; ">
;C-Dur-Tonleiter
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
%% s:3 = 3x so groß
%% f:1 zeigt Finger als Kreise
%% f:2 zeigt Finger neben den Saiten
%% 6-3-2 Saite-Bund-Finger
%% oder
%% 6-3-2 Saite-Bund-Intervall
%% 4-o zeigt 4. Saite offen
\fret-diagram #"s:3;f:1;
1-3-5; 1-5-6;
2-3-2; 2-5-3; 2-6-4;
3-2-6; 3-4-7; 3-5-1;
4-2-3; 4-3-4; 4-5-5;
5-2-7; 5-3-1; 5-5-2;
6-3-5; 6-5-6;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Du siehst selbst, dass die C-Dur-Tonleiter von der Form her eher wie die Bb-Dur-Tonleiter als wie die A-Dur-Tonleiter aussieht.
==== 3. Fingersatz II-V-I-Verbindung D-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;D-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:3;f:1;
4-9-7;4-10-1;4-12-2;
5-10-5;5-12-6;
6-10-2;6-12-3;6-13-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
{{clear}}
Wir beginnen oben bei der D-Form, wo sich der Lagewechsel des 3. Fingersatz noch nicht mit dem Lagewechsel zwischen der G und H-Saite (engl. B-Saite) aufhebt.
Würde ich ein Capo in den 10. Bund setzen, dann würde ich die Melodie vom Fingersatz her wie D-Dur spielen. In D-Dur spiele ich diese II-V-I-Verbindung Em7 A7 D. Nehme ich das Capo weg, dann greife ich den Dm(7) als einen Barré der Em-Form im 10. Bund. Von diesem kann ich mir das D als Grundton ableiten.
Alternativ siehst du in den Noten, dass die Übung mit dem Ton D anfängt. Dass die oberste Tiefe E-Saite im 12. Bund ebenfalls ein E ergibt, setze ich als bekannt voraus. Falls nicht, beschäftige dich noch einmal mit dem [[Gitarre: Lagerfeueranhang 2c|Stimmen der Gitarre]]. Ein Ganztonschritt bzw. zwei Bünde vor dem E ist der Ton D.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (D-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #9
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung G-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;G-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
3-4-7;3-5-1;3-7-2;
4-5-5;4-7-6;
5-5-2;5-7-3;5-8-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 5. Bund setzen, dann würde man die Melodie vom Fingersatz her wie G-Dur spielen. In G-Dur spielt man diese II-V-I-Verbindung Am7 D7 G. Nimmt man das Capo weg, dann greift man den Dm(7) als einen Barré der Am-Form. Von diesem kannst du dir den D als Grundton ableiten.
Einfacher geht es natürlich, wenn du weißt, dass der D im 5. Bund der A-Saite der Stimmton der D-Saite ist.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (G-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
\set TabStaff.minimumFret = #4
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g-1 a-4 b-1 c4 |
b8^\markup { \bold {G7} } a-4 g4-1 f8 e d4 |
e8^\markup { \bold {C} } f g4-1 a8-4 b-1 c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-0-7;2-1-1;2-3-2;
3-0-5;3-2-6;
4-0-2;4-2-3;4-3-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Die C-Dur-Form der C-Dur Tonleiter sieht schlicht und ergreifend wie die C-Durtonleiter aus.
</div>
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c {
% \set TabStaff.minimumFret = #4
% \set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. | \break
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
==== 3. Fingersatz II-V-I-Verbindung C-Form 12. Bund ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;C-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
2-12-7;2-13-1;2-15-2;
3-12-5;3-14-6;
4-12-2;4-14-3;4-15-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 12. Bund setzen, dann würde man die Melodie vom Fingersatz her wie C-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Dm7 G7 C.
Der Startton ist schlicht die D-Saite im 12. Bund.
</div>
{{clear}}
Gerade noch hatten wir einen Lagewechsel nach links. Jetzt aber hebt sich der Lagewechsel nach links vom 3. Fingersatz mit dem Lagewechsel zwischen der G- und H-Saite auf.
Es hört sich beim ersten Durchlesen kompliziert an, aber du hast nur 4 Lektionen zu lernen.
Den 1. bis 3. Fingersatz und den Lagewechsel zwischen der G- und H-Saite.
Das Auffinden der Töne und welche Akkorde zu welcher Tonart gehört, und wie man einen Capo benutzt, sollte eigentlich nichts neues für dich sein.
Rein technisch gesehen vereinfacht sich der Fingersatz. Doch es kostet ein wenig Überlegung, wie sich die beiden Lagewechsel auf den 3. Fingersatz auswirken.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (C-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #12
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
Sollte es im 12 Bund unbequem zu spielen sein, weil du kein Cutaway hast (Aussparung für die hohen Bünde), übe die C-Form ein paar Bünde zurück in einer anderen Tonart.
==== 3. Fingersatz II-V-I-Verbindung F-Form ====
<div style="float:left; padding:5px; margin:5px; border:black solid 1px; ">
;F-Form
<score raw="1">
\version "2.14.2"
\markup
\override #'(fret-diagram-details . ( (number-type . roman-upper)
(finger-code . in-dot) (orientation . landscape))) {
\fret-diagram #"s:1.5;f:1;
1-7-7; 1-8-1;1-10-2;
2-8-5; 2-10-6;
3-7-2; 3-9-3; 3-10-4;"
}
\paper{
indent=0\mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
bookTitleMarkup = ##f
scoreTitleMarkup = ##f}
</score>
</div>
<div style="float:left; padding:5px; margin:5px; <!-- border:black solid 1px; --> ">
Würde man ein Capo in den 6. Bund setzen, dann würde man die Melodie vom Fingersatz her wie F-Dur spielen. In C-Dur spielt man diese II-V-I-Verbindung Gm7 C7 F.
Wenn du den C wie ein F-Barré im 8. Bund greifst, dindest du den Grundton (1) auf der hohen E-Saite. Von dem wanderst du runter zum Startton (2).
</div>
{{clear}}
Auch hier hebt sich der Lagewechsel zwischen der G- und H-Saite mit dem Lagewechsel des 3. Fingersatz gegeneinander auf, was den Fingersatz grifftechnisch wieder vereinfacht.
<score sound="1" raw="1">
\version "2.20.0"
\header {
title="3. Fingersatz (F-Form) in C-Dur"
subtitle="Eine II-V-I-Verbindung"
}
%% Diskant- bzw. Melodiesaiten
Diskant = \relative c' {
\set TabStaff.minimumFret = #7
\set TabStaff.restrainOpenStrings = ##t
\key c \major
d8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
d,8^\markup { \bold {Dm7} } e f g a b c4 |
b8^\markup { \bold {G7} } a g4 f8 e d4 |
e8^\markup { \bold {C} } f g4 a8 b c d | c b c2. |
\bar "|."
}
%% Layout- bzw. Bildausgabe
\score {
<<
\new Voice {
\clef "treble_8"
\time 4/4
\tempo 4 = 120
\set Score.tempoHideNote = ##t
\Diskant
}
\new TabStaff { \tabFullNotation \Diskant }
>>
\layout {}
}
%% Midiausgabe mit Wiederholungen, ohne Akkorde
\score {
<<
\unfoldRepeats {
\new Staff <<
\tempo 4 = 120
\time 4/4
\set Staff.midiInstrument = #"acoustic guitar (nylon)"
\clef "G_8"
\Diskant
>>
}
>>
\midi {}
}
%% unterdrückt im raw="!"-Modus das DinA4-Format.
\paper {
indent=0\mm
%% DinA4 = 210mm - 10mm Rand - 20mm Lochrand = 180mm
line-width=180\mm
oddFooterMarkup=##f
oddHeaderMarkup=##f
% bookTitleMarkup=##f
scoreTitleMarkup=##f
}
</score>
== Wie geht es weiter? ==
Solltest du als Quereinsteiger in diese Lektion gestolpert sein, dann schaue dir die erste Lektion zum [[Gitarre: Aufbau der CAGED-Skalenformen|Aufbau der CAGED-Skalenformen]] an. Insbesondere die Abschnitte, die hier übergangen wurden. Dannach kannst du mit der ersten CAGED-Skala in der D-Dur-Form weitermachen.
<noinclude>
{{Navigation zurückhochvor
|zurücklink=Gitarre: CAGED-Skala G-Dur-Form
|zurücktext=CAGED-Skala G-Dur-Form
|hochlink=Gitarre: Die Major-Patterns
|hochtext=Einführung: Major-Patterns
|vorlink=Gitarre: CAGED-Skala D-Dur-Form
|vortext=CAGED-Skala D-Dur-Form
}}
</noinclude>
ezaviun9aicigme7umcm6fbjsv55ck1
Ing Mathematik: Python
0
117969
1090625
1090446
2026-09-09T16:32:05Z
Intruder
1513
/* Ein paar Worte zur Erklärung */ PYPL hinzu
1090625
wikitext
text/x-wiki
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
= Hallo Welt und allgemeine Hinweise =
== Was ist Python ==
* Python ist eine universelle höhere Programmiersprache.
* Python ist objektorientiert.
* Python ist Open-Source (Python Software Foundation License).
* Python ist für viele Betriebssysteme erhältlich (z.B. für Linux, MS Windows, macOS).
* Python ist ein Interpreter.
* Python ist durch Module fast beliebig erweiterbar.
* Python als Programmiersprache ist case-sensitive - d.h. Groß- und Kleinschreibung ist relevant bei der Eingabe von Befehlen.
* Python ist in etlichen Anwendungsprogrammen (z.B. {{W|FreeCAD}}, {{W|LibreOffice}}, {{W|GIMP}}, {{W|Blender (Software) | Blender}}) als Makrosprache verwendbar.
{{Wikipedia | Python (Programmiersprache)}}
== Python installieren ==
=== MS Windows ===
Laden Sie das aktuelle Python-Paket von der Webseite [https://www.python.org/] herunter. Weiter geht es wie bei jedem anderen größeren zu installierenden Programm. Einfach das Installationsprogramm im Explorer doppelklicken und den Anweisungen des Setup-Programmes folgen.
=== Linux ===
Entweder ist Python bereits standardmäßig installiert, ansonsten ist die Installation mittels Paketmanagementsystem einfach möglich. Aber auch die Spyder-Entwicklungsumgebung ([https://www.spyder-ide.org]) bietet einen guten Einstieg mit Python (das gilt auch für MS Windows). Spyder bringt auch schon etliche wichtige Module standardmäßig mit.
== Python starten ==
=== MS Windows ===
Das Icon für das Python-Programm doppelklicken. Und schon startet das Programm.
[[Datei:PythonIng_start1.jpg]]
Python im interaktiven Modus präsentiert sich dann so:
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
Alternativ kann das Programm auch über die Eingabeaufforderung oder die PowerShell gestartet werden:
c:\devel\Python>python.exe
Python 3.12.4 (tags/v3.12.4:8e8a4ba, Jun 6 2024, 19:30:16) [MSC v.1940 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>>
=== Linux ===
Tippen Sie einfach das Wort „python“ (oder unter openSUSE Tumbleweed z.B. auch „python3.11“ oder „python3.13“) in einem Linux-Terminal ein, schließen den Befehl mit der RETURN-Taste ab, und schon startet Python im interaktiven Modus:
Python 3.13.12 (main, Feb 09 2026, 22:37:44) [GCC] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
Es gibt auch noch andere Möglichkeiten Python zwecks Programmausführung zu starten, z. B. den {{W|Shebang}} (<code>#!</code>) am Beginn eines Python-Scripts. Das Script sei als Script.py gespeichert. Dann kann das Script mit ./Script.py ausgeführt werden. Für openSUSE Tumbleweed sei nachfolgend ein lauffähiges "Hallo Welt!"-Script angegeben. Es wird in diesem Script der Python-Interpreter in der Version 3.13 verwendet :
#!/usr/bin/python3.13
print("Hallo Welt!")
Die Berechtigungen zum Ausführen der Datei müssen natürlich noch richtig gesetzt werden, z.B. mittels <code>chmod 777 Script.py</code>. <small><code>chmod</code> ist die Abkürzung für"'''ch'''ange file '''mod'''e bits".</small>
<small>Die "Maske" <code>777</code> ist nur für Testzwecke sinnvoll, weil sie leicht zu merken ist und für alle Benutzer alle Zugriffsberechtigungen ('''r'''ead/'''w'''rite/e'''x'''ecute für owner/group/others) setzt. Im richtigen Einsatz wird man das aus Sicherheitsgründen nicht so handhaben, sondern nur die Berechtigungen setzen, die unbedingt erforderlich sind. Welche Zugriffsberechtigungen gesetzt sind, kann man z.B. mit dem Befehl <code>ls -l</code> oder <code>ll</code> ('''l'''i'''s'''t directory contents) erfragen. Aber dazu im Moment genug. Erfahrene Linux-Nutzer kennen das ohnehin und Anfänger sollen jetzt nicht mit Linux-Interna überfordert werden. Bei Bedarf siehe die Linux-Man-Pages oder dezidierte Bücher zu Linux.</code></small>
<small>Oder das Script wird in einen Pfad verschoben, in dem sich ausführbare Programme generell befinden (welche Verzeichnisse im PATH liegen, kann bspw. mit <code>echo $PATH</code> abgefragt werden). Das Script kann dann wie ein normales Programm ohne weitere Angaben mit Script.py gestartet werden. Alternativ wird nicht das Script an sich verschoben, sondern nur ein symbolischer Link angelegt, z.B. mit <code>ln -s ~/tmp/Script.py ~/.local/bin/Script.py</code>. <code>~/.local/bin</code> sei ein im PATH gelegenes Verzeichnis. Dies sind aber schon Features für fortgeschrittene Linux-Benutzer und werden am Anfang eher selten benötigt.</small>
== Ein paar Worte zur Erklärung ==
Getestet wurden die Beispiele unter den Betriebssystemen
* MS Windows 10 mit der Python-Version 3.12.0 (teilweise auch mit 3.12.2 und 3.13.1; nur die Inhalte die bis spätestens Juli 2025 erstellt wurden)
* MS Windows 11 ab der Python-Version 3.13.4 (nur zum Teil; ab Juli 2025)
* openSUSE Leap 15.6 mit der Python-Version 3.11.12 (Spyder, nur vereinzelt) und zum Teil mit 3.12.11 (ab Juli 2025 bis November 2025).
* openSUSE Tumbleweed ab der Python-Version 3.13.9 (nur vereinzelt, ab November 2025)
An Beliebtheit rangiert Python mit Stand August 2026 mit einem Rating von 18,53% an 1. Stelle vor C und C++ (lt. [https://www.tiobe.com/tiobe-index/ TPCI - TIOBE Programming Community Index]). Lt. [https://innovationgraph.github.com/global-metrics/programming-languages GitHub Top 50 Programming Languages Globally] lag Python im Q1/2026 auf Rang 2, vor TypeScript und hinter JavaScript. [https://pypl.github.io/PYPL.html PYPL] (Popularity of Programming Language Index) ist ein anderer Popularitätsindex für Programmiersprachen. Auch hier rangiert Python mit großem Vorsprung auf dem ersten Platz, gefolgt von Java und C/C++ (Stand August 2026).
Der Name "Python" rührt von der Komikertruppe {{W|Monty Python}} her. Die Icons für Python (z.B. Python selbst, Eric IDE, IDLE) sind aber durch die Python-Schlangenart symbolisiert.
<gallery>
Python-logo-notext.svg|Python-Logo
Guido van Rossum OSCON 2006.jpg|Guido van Rossum (geb. 1956), der Erfinder von Python
</gallery>
== Ein erstes Programm ==
Kommentare werden in Python mit der Raute (#) eingeleitet. Sie werden vom Python-Interpreter ignoriert. Text kann mit der print-Funktion ausgegeben werden. Starten Sie Python und geben sie folgende Anweisungen zeilenweise ein
>>> # Das ist ein Kommentar
>>> print("Hallo Welt!")
Als Ergebnis erhalten Sie
Hallo Welt!
Der Prompt (>>>) ist selbstverständlich nicht einzutippen, sondern wird vom Python-System geliefert.
Strings können in Python entweder in Anführungszeichen (") gesetzt werden oder in Hochkommatas('). In diesem Text wird die erste Variante bevorzugt eingesetzt.
Im Gegensatz zu Julia ist es hier egal, ob zwischen <code>print</code> und der öffnenden Klammer Leerzeichen stehen.
= Python als Taschenrechner =
== Allgemeines ==
Wir wollen 3 * 5 berechnen. Dazu starten wir Python im interaktiven Modus. Geben Sie dann die Formel
>>> 3 * 5
ein, drücken die Taste ENTER/RETURN ({{Taste|↵}}) und erhalten als Ergebnis
15
Auch kompliziertere Ausdrücke sind möglich. Beispielsweise mit Winkelfunktionen, Quadratwurzeln etc. Wir wollen nun den Ausdruck <math>\sin\sqrt{15}</math> berechnen :
>>> import math
>>> math.sin(math.sqrt(15))
-0.6679052983383519
Als erstes wird das math-Modul importiert. Dann wird der mathematische Ausdruck berechnet.
Eine andere Variante, die dasselbe Ergebnis liefert, ist
>>> from math import *
>>> sin(sqrt(15))
-0.6679052983383519
Es wird also aus dem Modul <code>math</code> alles importiert (erkennbar am <code>*</code>). Will man nicht alles importieren, so kann man das auch einschränken:
>>> from math import sin, sqrt
Beenden lässt sich das Python-Programm durch Eingabe von <code>exit()</code> (und natürlich ist zur Bestätigung die RETURN-Taste zu drücken).
== Die Hilfefunktion von Python ==
Bei Eingabe der Anweisung <code>help</code> oder <code>help()</code> springt Python in den Hilfemodus.
Eingabe:
>>> help()
Eingabe:
help> math.sin
Ausgabe:
Help on built-in function sin in math:
math.sin = sin(x, /)
Return the sine of x (measured in radians).
Für die komplette Python-Dokumentation siehe [https://docs.python.org/3/]. Verlassen kann man den Hilfemodus durch das Drücken von STRG-C, bzw. der Eingabe von q, quit oder exit mit anschließendem Drücken der RETURN-Taste.
== Aufgaben ==
* Erkunden Sie die Tangensfunktion "tan" mittels Python-Hilfe (vergessen Sie nicht das math-Modul zu importieren und das <code>math.</code> vor <code>tan</code>)
* Berechnen Sie mit Python den Ausdruck <math>\frac{1}{2}\cdot \text{e}^2 \cdot \tan(\pi/3)</math>. Siehe für die Exponentialfunktion im Python-Hilfesystem auch den Befehl <code>math.exp</code>. Alternativ kann auch die Konstante <code>math.e</code> eingesetzt werden. Potenzieren kann man bei Python mit dem **-Operator (z.B. 2**3 = 8). Für <math>\pi</math> gibt es <code>math.pi</code>.
= Python als Scriptsprache =
Häufig wird man aber kompliziertere Anweisungsfolgen verarbeiten müssen. Diese will man normalerweise nicht jedesmal neu eingeben, sondern in einer Datei speichern und diese Datei dann zur Ausführung bringen. Speichern Sie dazu folgenden Code in einer Textdatei, z.B. unter MS Windows als c:\tmp\test1.py
# Das ist ein Kommentar
print("Hallo Welt!")
Python-Dateien werden mit der Dateiendung .py versehen. Achten Sie darauf, dass vor dem print keine Leerzeichen vorhanden sind. Das ist eine Python-Eigenheit. Wie wir später sehen werden, nutzt Python Einrückungen als syntaktisches Mittel, z.B. um bei Schleifen den Schleifenkörper zu kennzeichnen.
Danach bringen Sie die Skriptdatei test1.py (sozusagen das Hauptprogramm) folgendermaßen zur Ausführung:
1) Starten Sie unter MS Windows die Eingabeaufforderung (oder alternativ auch die Windows PowerShell). Das sieht dann etwa so aus:
Microsoft Windows [Version 10.0.19045.3693]
(c) Microsoft Corporation. Alle Rechte vorbehalten.
C:\Users\xyz>
: <small>Falls jemand nicht weiß, wie man die Eingabeaufforderung startet: Eine Möglichkeit ist, einfach in der Taskleiste von Windows das "Start"-Symbol ([[Image:Windows_logo_-_2021_(Black).svg|10px]]) mit der rechten Maustaste anklicken. "Ausführen" auswählen (oder alternativ für die PowerShell unter Windows 10 den Eintrag "Windows PowerShell", unter Windows 11 den Eintrag "Terminal"). Im sich öffnenden Dialogfenster gibt man in die "Öffnen"-Zeile das Wort <code>cmd</code> ein und mit "OK" wird das Ganze bestätigt.</small>
2) Wechseln Sie mittels <code>cd c:\tmp</code> in das Verzeichnis c:\tmp
3) Angenommen, Sie haben Python unter dem Pfad <code>c:\devel\Python\</code> installiert. Starten Sie das Programm so (der Prompt <code>c:\tmp></code>ist natürlich nicht mit einzutippen):
c:\tmp>c:\devel\Python\python.exe test1.py
4) Wie erwartet ergibt sich folgende Ausgabe am Bildschirm
Hallo Welt!
Die Vorgehensweise unter Linux ist prinzipiell gleich. Die kleinen Unterschiede, wie z.B. der Slash statt dem Backslash in Pfadangaben, sollten für Linux-Benutzer keine Hürde darstellen.
== Variablen ==
Variablenbezeichner können aus Buchstaben (A-Za-z), Ziffern (0-9) und Underscores (_) bestehen, dürfen aber nicht mit einer Zahl beginnen. Führende Underscores haben u.a. im Kontext mit der Objektorientierten Programmierung eine spezielle Bedeutung und sollten nicht für "normale" Variablenbezeichner verwendet werden.
Gültige Variablenbezeichner wären also:
xyz
x1
_wert
name_anzahl
Theoretisch kann man auch Umlaute, griechische Buchstaben u.ä. in Variablenbezeichnern nutzen, z.B.
ößÜ = 16
α = 134
print(ößÜ)
print(α)
Ausgabe:
16
134
Davon wird aber aus offensichtlichen Gründen ({{W|Englisch als Lingua franca}}) abgeraten. Das Eurozeichen (€) etc. darf man ohnehin nicht in Variablenbezeichnern verwenden, dies ergäbe einen Syntaxfehler. Siehe dazu auch [https://peps.python.org/pep-3131/].
Es gibt in Python etliche Schlüsselwörter (z.B. for, if oder return). Diese dürfen nicht als eigene Variablenbezeichner verwendet werden. Eine Liste aller Schlüsselwörter liefert das Script
import keyword
print(keyword.kwlist)
<small>Übung: Speichern Sie dieses Script in eine Datei, z.B. in c:\tmp\test1.py. Führen Sie diese Datei aus, um die Liste der Schlüsselwörter auszugeben.</small>
Da Python case-sensitiv ist, repräsentieren folgende Bezeichner verschiedene Variablen:
xyz
XYZ
xYz
Werte werden an Variablen mittels Gleich-Zeichen (=) zugewiesen. Im Folgenden wird der Code immer in der Datei c:\tmp\test1.py gespeichert.
x = 5
y = 10
z = x*y
print(z)
Bringen Sie die Datei test1.py zur Ausführung, so erhalten Sie folgende Bildschirmausgabe
50
Sie können auch mehrere Anweisungen in einer Zeile durch Semikolon getrennt schreiben. Dies führt aber zu unübersichtlichem Code.
x = 5; y = 10; z = x*y; print(z)
Ausgabe:
50
Auch aus der Programmiersprache C/C++ oder Java bekannte Konstrukte können Sie verwenden, z.B.
x = 5
# x = x - 2
x -= 2
print(x)
Bildschirmausgabe:
3
Beachten Sie, dass mit dem =-Zeichen eine Wertezuweisung durchgeführt wird. Dies ist nicht äquivalent zum mathematischen =-Zeichen, wie am vorigen Beispiel zu ersehen ist. Den Inkrement-/Dekrementoperator (z.B. x++ oder x--) aus C/C++ oder Java kennt Python aber nicht.
Variablen sind nicht an einen bestimmten Datentyp gebunden, folgendes ist mit Python problemlos möglich:
import math
wert = 10
print(wert)
wert = 35.5
print(wert)
wert = "Hallo"
print(wert)
wert = math.pi
print(wert)
Ausgabe:
10
35.5
Hallo
3.141592653589793
== Physische und logische Zeilen ==
In Python muss eine Anweisung in einer logischen Zeile Platz finden. Wird eine Anweisung aber zu lang für eine Zeile, dann kann sie in mehrere physische Zeilen unterteilt werden. Dies kann einerseits durch einen Backslash am Ende einer Zeile geschehen, z.B.
a = 2 + \
5
Dies stellt eine logische Zeile dar, die in zwei physische Zeilen unterbrochen ist.
Geklammerte Ausdrücke werden automatisch zu einer logischen Zeile verbunden, z.B.
a = (2 +
5)
Achtung: Im ersten Beispiel darf nach dem Backslash nichts mehr stehen, auch kein Kommentar. Dies trifft im zweiten Bespiel nicht zu, hier könnte noch ein Kommentar folgen, z.B.
a = (2 + # Kommentar
5)
Auch für Strings gibt es Möglichkeiten, diese auf mehrere Zeilen aufzuspalten.
# Kurzer String
str1 = "ABC"
# Langer String
str2 = """Hallo Welt,
Grüetzi Schwyzer,
Servus an alle"""
# Backslash
str3 = "UVW\
XYZ"
# Mit Klammern
str4 = ("Sehr langer Text, der automatisch .............. "
"in einer einzigen Variable zusammengefügt wird."
)
print(str1)
print(str2)
print(str3)
print(str4)
Ausgabe:
ABC
Hallo Welt,
Grüetzi Schwyzer,
Servus an alle
UVWXYZ
Sehr langer Text, der automatisch .............. in einer einzigen Variable zusammengefügt wird.
==Hexadezimale, oktale, binäre und andere Zahlen==
d = 1050 # Dezimalzahl
h = 0xAA2 # Hexadezimalzahl
o = 0o12 # Oktalzahl
b = 0b100001101 # Binärzahl
print(d)
print(h)
print(o)
print(b)
Ausgabe:
1050
2722
10
269
Groß- und Kleinbuchstaben sind in obigen Literalen übrigens egal. So kann man z.B. statt <code>0b1001</code> auch <code>0B1001</code> schreiben (siehe dazu [https://docs.python.org/3/reference/lexical_analysis.html#integer-literals]).
Sie können auch dezimale in hexadezimale Zahlen umwandeln, usw.:
h = hex(1050) # Dezimalzahl -> Hexadezimalzahl
b = bin(1050) # Dezimalzahl -> Binärzahl
o = oct(1050) # Dezimalzahl -> Oktalzahl
print(h)
print(b)
print(o)
Ausgabe:
0x41a
0b10000011010
0o2032
Gegeben sei die Zahl 121 zur Basis 3. Diese soll in eine Dezimalzahl umgewandelt werden. Das kann so geschehen:
z = int("121", 3)
print(z)
Ausgabe:
16
Dass dies richtig ist, davon kann man sich folgendermaßen überzeugen:
<math> 1 \cdot 3^2 + 2 \cdot 3^1 + 1 \cdot 3^0 = 9 + 6+ 1 = 16 </math>
Zahlen übersichtlicher schreiben kann man auch mittels Underscore, z.B.:
print("Eine Million (Variante 1) =", 1000000)
print("Eine Million (Variante 2) =", 1_000_000)
print("Eine Rechnung:", 2_000 * 400_000);
Es ergibt sich bei beiden Varianten die gleiche Ausgabe. Variante 2 ist aber im Sourcecode leichter lesbar, detto die Zahlen in der Rechnung:
Eine Million (Variante 1) = 1000000
Eine Million (Variante 2) = 1000000
Eine Rechnung: 800000000
== Strings und Platzhalter==
Ein paar einfache Beispiele:
print("Hallo {}" . format("Hugo"))
print("Hallo {:s}" . format("Hugo"))
print("Hallo %s" % "Hugo")
Ausgabe:
Hallo Hugo
Hallo Hugo
Hallo Hugo
Python-Code (formatted string literals, Beispiel 1):
str1 = "Hallo"
str2 = "Hugo"
print(f"{str1} {str2}")
Ausgabe:
Hallo Hugo
Python-Code (formatted string literals, Beispiel 2):
wert = 11.567
print(f"Ausgabe: {wert:.5f}")
Ausgabe:
Ausgabe: 11.56700
Komplexere Beispiele:
print("Hallo {} und {}" . format("Hugo", "Mike"))
print("Hallo {name1} und {name2}" . format(name2="Hugo", name1="Mike"))
# Füllzeichen: *
# Bündigkeit: > (=rechts), < (=links), ^ (=zentriert)
# Feldweite: 10
# Typ: s (=String), f (=Gleitkommazahl), d (=Dezimalzahl) etc.
print("Hallo {:*>10s}" . format("Hugo"))
print("Hallo {:*<10s}" . format("Hugo"))
Ausgabe:
Hallo Hugo und Mike
Hallo Mike und Hugo
Hallo ******Hugo
Hallo Hugo******
Python-Code:
str = "Hallo\t%s\t%7.2f\t%10.2e\t%i" % ("Hugo", 12.34567, 34.567, 264)
print(str)
Ausgabe:
Hallo Hugo 12.35 3.46e+01 264
== Unicode ==
Neben den bekannten ASCII-Zeichen lassen sich Zeichen auch mittels Unicode beschreiben. Griechische Buchstaben oder komplexere mathematische Operatoren - all das sollte kein Problem sein. Siehe auch {{W|Unicode}}, {{W|Liste der Unicodeblöcke}} und {{W|Unicodeblock Mathematische Operatoren}}. Im Folgenden werden ein paar Zeichen (Allquantor, Nabla-Operator, Existenzquantor), die man aus der Mathematik kennt, erzeugt.
ch1 = "\N{FOR ALL}"
ch2 = "\N{NABLA}"
ch3 = "\u2203"
print(ch1, ch2, ch3)
Ausgabe:
∀ ∇ ∃
<small>Diese Ausgabe ergibt sich z.B. mit der IDLE-Shell oder mit Cygwin. Beim Ausführen über die Windows-Eingabeaufforderung oder Windows PowerShell unter MS Windows 10 erfolgt keine korrekte Darstellung. IDLE ist die mit Python mitgelieferte IDE ('''I'''ntegrated '''D'''evelopment '''E'''nvironment, Integrierte Entwicklungsumgebung). Gegen Ende dieses Textes wird IDLE kurz beschrieben.
Das Problem mit der Windows Eingabeaufforderung lässt sich aber umgehen. Man muss nur eine Schriftart auswählen, die die Zeichen kennt, z.B. "DejaVu Sans Mono". Dazu klicken Sie einfach bei der Eingabeaufforderung mit der rechten Maustaste oben auf die weiße Leiste und wählen im aufpoppenden Fenster den Menüpunkt "Eigenschaften". Es öffnet sich ein Dialogfenster. Über den Reiter "Schriftart" lässt sich nun die Schriftart einstellen. Unter MS Windows 11 oder openSUSE Leap 15.6 (bash-Konsole) gibt es dieses Problem ohnehin nicht.</small>
== Reguläre Ausdrücke ==
Python kennt auch {{W|Regulärer Ausdruck|reguläre Ausdrücke}}. Dazu gibt es in Python das Modul <code>re</code>. Beipielsweise sollen alle Zahlen (<math>\text{zahl}\in\mathbb{N}_0</math>) in einem String gesucht und ausgegeben werden. Als String sei gegeben: <code>3x Grüße und 100 Kekse.</code> Das Muster (Pattern) ist <code>\d+</code>. <code>\d</code> steht für eine Dezimalziffer 0-9. Das Plus-Zeichen (+) steht symbolisch für ein oder mehrere Zeichen des vorherigen Ausdrucks. Hier also ein oder mehrere Dezimalziffern. Es wird die Funktion <code>findall</code> aus dem Modul <code>re</code>verwendet.
Python-Code:
from re import findall
str = "3x Grüße und 100 Kekse."
pat = "\\d+" # Doppel-Backslashes müssen verwendet werden, sonst gibt Python eine Warnung aus!
# alternativ: pat = r"\d+"
# oder: pat = "[0-9]+"
numb = findall(pat, str)
print(numb)
Ausgabe:
['3', '100']
Python kennt noch viele weitere Möglichkeiten mittels regulärer Ausdrücke zu hantieren. Dies soll hier aber nicht vertieft werden, da das Thema schon ziemlich speziell und komplex ist. Bei Bedarf siehe aber z.B. die Bücher ''Weigend, Seite 380ff'' und ''Ernesti, Kaiser'' [https://openbook.rheinwerk-verlag.de/python/28_001.html] oder die Python-Dokumentation [https://docs.python.org/3/library/re.html]. Auch [[Python unter Linux: Reguläre Ausdrücke]] liefert ein umfangreiches und brauchbares Python-2-Kapitel zu den regulären Ausdrücken. Die dort gelisteten Beispiele müssten ggf. vor Verwendung auf Python-3 umgeschrieben werden. <small>Wie macht man das? Dazu siehe z.B. [https://openbook.rheinwerk-verlag.de/python/43_001.html], [https://portingguide.readthedocs.io/en/latest/] oder [https://www.digitalocean.com/community/tutorials/how-to-port-python-2-code-to-python-3]</small>
<small>Es gibt auch ein externes Modul ''regex'', das bei Bedarf extra installiert werden muss ([https://pypi.org/project/regex/]). Es bietet zusätzliche Funktionalität und gründlicheren Unicode-Support. Dies sei hier aber nur der Vollständigkeit halber erwähnt.</small>
== Verzweigungen ==
=== if ===
Die IF-Verzweigung sei aus anderen Programmiersprachen bereits bekannt. In {{W|Pseudocode}} lässt sie sich folgendermaßen darstellen:
WENN bedingung TRUE
führe block1 aus
SONST
führe block2 aus
ENDE
Als {{W|Aktivitätsdiagramm|UML-Aktivitätsdiagramm}} sieht das in etwa so aus:
[[File:If-Then-Else-diagram.svg|200px]]
Und als {{W|Nassi-Shneiderman-Diagramm|Nassi-Shneiderman-Struktogramm}} so:
[[File:Zweiseitige Auswahl.png|250px]]
In Python gibt es keinen expliziten ENDE-Kennzeichner. Stattdessen wird der Code durch Einrückungen strukturiert. Alles mit der gleichen Einrückungstiefe gehört zum selben Block. Dies zeichnet Python vor anderen Programmiersprachen aus.
Die test1.py-Datei laute also wie folgt:
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
Der else-Zweig wird ausgefuehrt
x ist groesser oder gleich 4
Man achte auch auf die Doppelpunkte in der if- und else-Zeile. Darauf vergisst man gerne, wenn man von anderen Programmiersprachen kommt.
Folgendes wäre in Python ein Fehler (genauer gesagt ein IndentationError).
x = 5
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Auch Nachstehendes würde nicht zum gewünschten Ergebnis führen (löst aber keine Fehlermeldung aus). Der letzte print-Befehl ist schon außerhalb der IF-ELSE-Verzweigung.
x = 3
if x < 4:
print("x ist kleiner als 4")
else:
print("Der else-Zweig wird ausgefuehrt")
print("x ist groesser oder gleich 4")
Ausgabe:
x ist kleiner als 4
x ist groesser oder gleich 4
Python kennt eine Reihe von Vergleichs- und Verknüpfungsoperatoren:
<, <= ... kleiner (gleich)
>, >= ... größer (gleich)
== ... gleich
!= ... ungleich
is ... identisch
is not ... nicht identisch
and ... AND
or ... OR
not ... NOT
Beispielsweise:
a = 5
b = 9
if a<=10 and b!=7:
print("OK")
else
print("Nicht OK")
Ausgabe:
OK
Der else-Block kann übrigens auch ersatzlos entfallen. Als Pseudocode sieht das so aus
WENN bedingung TRUE
führe block aus
ENDE
Mehrfache Verzweigungen werden durch das elif-Konstrukt erstellt. In Pseudocode:
WENN bedingung1 TRUE
führe block1 aus
SONST WENN bedingung2 TRUE
führe block2 aus
SONST WENN bedingung3 TRUE
führe block3 aus
SONST
führe block4 aus
ENDE
Ein Python-Beispiel:
a = 14
if a<=10:
print("<=5")
elif a>11 and a<15:
print("11 bis 15")
elif a>16 and a<20:
print("16 bis 20")
else:
print(">=20")
Ausgabe:
11 bis 15
In Python gibt es auch die Schlüsselwörter <code>True</code> (für wahr) und <code>False</code> (für falsch). Man beachte, dass sie mit Großbuchstaben beginnen. Andere Schreibweisen wären ein Fehler. Sie gehören zum Datentyp <code>bool</code>. Ihnen sind auch die Zahlen <code>1</code> und <code>0</code> zugewiesen.
Man beachte, dass {{W|Rundungsfehler}} auftreten können. D.h. man sollte bei der Verwendung von {{W|Gleitkommazahl|Gleitpunktzahlen}} niemals auf absolute Genauigkeit prüfen, sondern eine Toleranz (einen <math>\varepsilon</math>-Wert) vorgeben.
Ein klassisches Beispiel, das ein falsches Ergebnis liefert, ist:
i = 0.1 + 0.2
print(i)
if i == 0.3:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
NOK
Und das, obwohl man schon in der Volksschule lernt, dass 0.1 + 0.2 gleich 0.3 ist.
Korrekt muss das obige Beispiel z.B. so umgeschrieben werden:
ist = 0.1 + 0.2
soll = 0.3
epsilon = 0.000001
print(ist)
if abs(ist-soll) < epsilon:
print("OK")
else:
print("NOK")
Ausgabe:
0.30000000000000004
OK
Alternativ kann auch die <code>math.isclose()</code>-Funktion verwendet werden. Das sei aber hier nur erwähnt und nicht konkret ausgeführt.
<u>Aufgabe:</u> Recherchieren Sie im Internet zum Thema <code>math.isclose()</code>-Funktion.
=== match ===
Ab Python 3.10 gibt es auch die match-Anweisung. Dies ist das Python-Pendant für die switch-Anweisung in anderen Programmiersprachen, geht aber bei näherer Betrachtung weit darüber hinaus. Hier nur ein einfaches Beispiel:
x = "Hello"
match x:
case "Servus" | "Ciao": # or
print("Servus an alle")
case "Grüetzi":
print("Grüetzi Schwyzer")
case _: # other, default, sonstiges ...
print("Hallo Welt")
Ausgabe:
Hallo Welt
Als Struktogramm sieht das in etwa so aus:
[[File:Mehrseitige Auswahl.png|250px]]
Für nähere Details siehe z.B. [https://www.geeksforgeeks.org/python-match-case-statement/], [https://learnpython.com/blog/python-match-case-statement/], [https://docs.python.org/3/tutorial/controlflow.html#match-statements] und das Python Enhancement Proposal (PEP) 636 – Structural Pattern Matching: Tutorial [https://peps.python.org/pep-0636] und dort insbesondere den Anhang A - Quick Intro.
<small><code>match, case, _</code> etc. sind sogenannte ''soft keywords''. Im Gegensatz zu den normalen Schlüsselwörtern dürfen ihnen auch Werte zugewiesen werden. Eine Liste der weichen Schlüsselwörter lässt sich durch <code>keyword.softkwlist</code> erstellen (die Anweisung gibt es seit Python 3.9). Siehe dazu auch [https://stackoverflow.com/questions/65800344/what-are-soft-keywords] und [https://docs.python.org/3/library/keyword.html#keyword.softkwlist].</small>
== Schleifen ==
Kopfgesteuerte Schleife, Endlosschleife und fußgesteuerte Schleife:
[[File:Programmingloops.svg|450px]]
=== while ===
Die WHILE-Schleife ist kopfgesteuert. Sie funktioniert wie aus anderen Programmiersprachen bekannt.
In Pseudocode:
SOLANGE bedingung TRUE
führe block aus
ENDE
In Python:
x = 0
while x <= 10:
print(x)
x += 1
Ausgabe:
0
1
2
3
4
5
6
7
8
9
10
Eine Endlosschleife ergibt sich z.B. so:
i = 5
while True:
print(i)
i-=1
Beendet werden kann sie mit der Tastenkombination STRG-C.
Eine fußgesteuerte Schleife kann so simuliert werden:
i = 5
while True:
print(i)
i-=1
if i<=0:
print("Fire")
break
Ausgabe:
5
4
3
2
1
Fire
Der <code>break</code>-Befehl wird etwas später noch einmal kurz thematisiert.
=== for ===
Struktogramm einer for-Schleife:
[[File:Zählschleife.png|200px]]
In Python bspw. so:
for x in range(6):
print(x*2)
Ausgabe:
0
2
4
6
8
10
Die Schleife läuft von 0 bis 5. Ausgegeben wird jeweils der Wert x*2. Aquivalent kann diese Schleife auch so geschrieben werden:
for x in range(0, 11, 2):
print(x)
Die Ausgabe ist wie oben. Der Startwert sei 0, der Endwert ist 11-1 und die Schrittweite ist 2.
Ein anderes Beispiel sei
for x in "text":
print(x)
Ausgabe:
t
e
x
t
== Schleifen abbrechen ==
=== break ===
<code>break</code> bricht die Schleife ab und setzt mit dem nächsten Befehl außerhalb der Schleife fort.
for var in range(100):
print(var)
if var == 5:
break
Ausgabe:
0
1
2
3
4
5
=== continue ===
<code>continue</code> bricht den aktuellen Schleifendurchlauf ab und setzt mit dem nächsten Schleifendurchlauf fort.
for var in range (11):
if var == 5:
continue
print(var)
Ausgabe:
0
1
2
3
4
6
7
8
9
10
== try - except ==
try:
z1 = 12 / 0
print(z1)
except ZeroDivisionError:
print("Das Ergebnis ist unendlich")
except:
print("Kann nicht berechnet werden!")
print("Bitte die Formel korrigieren!")
print("Setze Programm fort!)
Ausgabe:
Das Ergebnis ist unendlich
Setze Programm fort!
Es wird versucht, eine Zahl durch Null zu dividieren. Das ist nicht möglich, es wird eine Ausnahme ausgelöst. Das Programm springt daher in den except-ZeroDivisionError-Block und führt die dort gelisteten Anweisungen aus (in unserem Fall eine print-Anweisung). Danach wird das Programm fortgesetzt. Würden wir dieses Programm ohne try-except ausführen, so ergibt sich aus
z1 = 12 / 0
print(z1)
folgende Fehlermeldung und ein unmittelbarer Programmabbruch
Traceback (most recent call last):
File "C:\tmp\test1.py", line 1, in <module>
z1 = 12 / 0
ZeroDivisionError: division by zero
Mit dem try-except-Mechanismus können also Ausnahmen oder Fehler aufgefangen und behandelt werden. In unserem Beispiel ist das eher trivial, aber bei größeren Programmen kann das durchaus Sinn machen.
== pass ==
Ein leerer Block muss in Python mittels dem Schlüsselwort <code>pass</code> dargestellt werden. Z.B.
x = 2
if x == 1:
print("Wert ist ", x)
else:
pass
Würde man das <code>pass</code> im else-Block weglassen, so würde man eine Fehlermeldung erhalten:
IndentationError: expected an indented block after 'else' statement on line 5
= Funktionen =
== Aufrufen von Funktionen ==
Funktionen sind uns im Rahmen dieses Kurses schon zuhauf begegnet. Sei es die print()-, die math.sin()- oder die hex()-Funktion. All diese Funktionen werden von Python zur Verfügung gestellt, ohne dass man sie explizit programmieren müsste. Aufgerufen werden diese Funktionen, indem man ihren Namen eintippt, gefolgt von runden Klammern. In diesen Klammern können noch Argumente übergeben werden. Auch Rückgabewerte sind möglich.
== Funktionen selber schreiben ==
Funktionen werden mit dem def-Schlüsselwort (man definiert die Funktion) eingeleitet, danach folgt der Funktionsname, danach wiederum runde Klammern, in denen formale Argumente stehen können. Abgeschlossen wird die def-Zeile mit einem Doppelpunkt. Danach folgt der Funktionskörper. Dieser Funktionskörper muss wiederum eingerückt werden (wie von den Verzweigungen und Schleifen bekannt). Aufgerufen wird diese Funktion, indem man ihren Funktionsnamen eingibt, gefolgt von runden Klammern (ggf. mit den aktuellen Parametern). Z.B.
# Funktion definieren
def halloWelt(i):
# i ... beliebige Ganzzahl
print("Hallo " * i, end="")
print("Welt!")
# Funktion aufrufen
halloWelt(3)
Ausgabe:
Hallo Hallo Hallo Welt!
Unterschied zwischen formalen und aktuellen Parametern:
[[Datei:PythonIng_func1.jpg]]
<small>Aktuelle Parameter werden auch Argumente genannt.</small>
Rückgabe von Funktionswerten:
# Funktion definieren
def mathFunc(a, b):
r1 = a + b
r2 = a * b
return r1, r2
# Funktion aufrufen
c, d = mathFunc(3, 5)
# Ausgabe der zurückgegebenen Werte
print(c)
print(d)
Ausgabe:
8
15
Es werden r1 und r2 zurückgegeben und den Variablen c und d zugewiesen. (r1, r2) und (c, d) sind Tupel. Was Tupel konkret sind, siehe etwas später in diesem Kapitel. 3 und 5 sind die aktuellen Parameter (die Argumente). a und b sind die formalen Parameter. Die Zuweisung der aktuellen zu den formalen Parametern erfolgt in der gegebenen Reihenfolge, also die Zahl 3 wird an a übergeben und die Zahl 5 an b.
Vorgabeparameter, z.B.:
def mathFunc(a=10, b=20):
r1 = a + b
r2 = a * b
return r1, r2
c, d = mathFunc(3, 5)
print(c)
print(d)
e, f = mathFunc(5)
print(e)
print(f)
g, h = mathFunc(b=6)
print(g)
print(h)
Ausgabe:
8
15
25
100
16
60
Erklärung:
* Erster <code>mathFunc</code>-Aufruf: Es werden, wie weiter oben, die Argumente 3 und 5 an die formalen Parameter a und b übergeben. Die Rückgabewerte r1 und r2 werden an c und d übergeben. Somit ist c=8 und d=15.
* Zweiter <code>mathFunc</code>-Aufruf: Es wird nur das Argment 5 an a übergeben. b behält den Vorgabewert 20. D.h. e= 25 und f=100.
* Dritter <code>mathFunc</code>-Aufruf: Es wird nur die Zahl 6 an b übergeben, a behält seinen Vorgabewert 10. Somit ergibt sich g=16 und h=60.
Beispiel (Schlüsselwortargumente vs. Positionsargumente):
def mathFunc(a, b):
r1 = a - b
r2 = a / b
return r1, r2
c, d = mathFunc(b=3, a=5) # Schlüsselwortargumente
e, f = mathFunc(3, 5) # Positionsargumente
print(c)
print(d)
print(e)
print(f)
Ausgabe:
2
1.6666666666666667
-2
0.6
Durch die Verwendung von Schlüsselwortargumenten können die Argumente in beliebiger Reihenfolge angegeben werden. Bei den Positionsargumenten ist die Reihenfolge vorgegeben. Daraus resultiert auch der Unterschied bei den obigen Ausgaben. Werden beide Arten in einem Aufruf gemischt, so müssen die Positionsargumente zuerst angegeben werden. Den Unterschied zwischen beiden Argumentarten zu kennen ist wichtig, nicht nur bei selbst erstellten Funktionen. Auch beim Aufruf von Python-Funktionen verfolgt einen die Mischung von Schlüsselwort- und Positionsargumenten auf Schritt und Tritt, z.B. beim etwas später folgenden Abschnitt über "Grafiken zeichnen":
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
Bei dieser <code>plot</code>-Funktion aus dem Modul <code>matplotlib.pyplot</code> sind <code>x</code> und <code>y1</code> Positionsargumente. <code>label, lw</code> und <code>ls</code> sind die Namen der Schlüsselwortargumente. Die Schlüsselwortargumente könnten auch in anderer Reihenfolge angeschrieben werden, nicht jedoch die Positionsargumente!
Siehe zu <code>matplotlib.pyplot.plot</code> auch die Seite [https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html].
== Lambda-Funktionen ==
print((lambda a, b: a*b) (3, 5))
Ausgabe:
15
Eingeleitet wird eine Lambda-Funktion (auch Lambda-Form, Lambda-Operator oder anonyme Funktion genannt) mit dem Schlüsselwort <code>lambda</code>. Es folgen die formalen Argumente, danach ein Doppelpunkt, die Berechnungsvorschrift und ggf. abschliessend in Klammern die aktuellen Parameter.
Man kann einer Lambda-Funktion auch einen Funktionsnamen geben und die Funktion über diesen Namen aufrufen, z.B.
prod = lambda a, b: a*b
print(prod(3, 5))
Als Ausgabe wird wieder die Zahl 15 geliefert.
== Rekursive Funktionen ==
Funktionen können wiederum andere Funktionen aufrufen. Von einem rekursiven Funktionsaufruf spricht man, wenn die aufgerufene Funktion gleich der aufrufenden ist.
def printFunc(i):
if (i >= 5):
return
else:
print("Hallo Welt")
printFunc(i+1)
printFunc(1)
Ausgabe:
Hallo Welt
Hallo Welt
Hallo Welt
Hallo Welt
== Funktionsannotationen ==
Python ist sehr flexibel, was Typen angeht. Im Vorhergehenden haben wir generell keine Typangaben gemacht. Will man Typen angeben, so bietet Python das Konzept der Funktionsannotation.
def calcFunc(a: int, b: int) -> int:
return a+b
r1 = calcFunc(8, 9)
r2 = calcFunc(8.0, 9.0)
r3 = calcFunc("Hallo", "Welt")
print(r1)
print(r2)
print(r3)
Ausgabe:
17
17.0
HalloWelt
Jetzt sieht man auf den ersten Blick, welche Typen der Programmierer im Sinn hatte, als er die Funktion erstellte. Das Problem dabei ist nur, dass es Python ziemlich egal ist, welche Typen man im Endeffekt eingibt. Im obigen Beispiel können statt Integer-Typen u.a. auch Float- oder String-Typen eingegeben werden.
<small>
Siehe zum Thema "Type Checking" aber auch den später folgenden Abschnitt [[Ing_Mathematik:_Python#Type_Checker]].
</small>
== Variadische Funktionen ==
Python-Code:
def test1(a, *b):
print(a);
for c in b:
print(c);
test1("Hallo", "Welt", "Schweizer", "und alle anderen")
Ausgabe:
Hallo
Welt
Schweizer
und alle anderen
Mit dem Stern (auch als Splat-Operator bezeichnet) in der formalen Parameterliste bei der Funktion <code>test1</code> wird angezeigt, dass eine beliebige Anzahl von Argumenten übergeben wird. <small> Dies entspricht in etwa dem, was in anderen Programmiersprachen (PHP etc.) mittels Ellipse (<code>...</code>) angezeigt wird.</small>
= Tupel, Listen und andere =
[[Datei:Python 3. The standard type hierarchy.png|mini|hochkant=1.7|Datentypen und Strukturen]]
== Tupel und Listen ==
Tupel, Listen und einige andere sind Datenstrukturen oder Sequenzen.
Listen (z.B. eine Einkaufsliste) sind veränderbar (mutable). Ein Tupel kann dagegen nicht verändert werden (immutable). Listen werden beim Anlegen in eckige Klammern eingeschlossen, Tupel in runde Klammern. Beim Tupel können die Klammern auch weggelassen werden. Ein Tupel mit nur einem Element muss mit einem Beistrich abgeschlossen werden. Der Grund ist, dass Python sonst nicht entscheiden kann, ob ein Tupel angelegt werden soll, oder nur ein geklammerter Wert.
Als Gedächtnisstütze kann man sich den Unterschied zwischen Tupel und Liste ev. so leichter merken:
: T'''u'''pel ... r'''u'''nde Klammern, '''u'''nveränderlich
: L'''i'''ste ... eck'''i'''ge Klammern, veränderl'''i'''ch.
Nachfolgend werden einige Operationen mit Listen und Tupel dargestellt.
# Liste und Tupel
liste = [1, 2, "Hallo"]
tupel = (1, 2, "Hallo")
# Ausgabe von liste und tupel
print(liste)
print(tupel)
# Ausgabe von Einzelelementen
print(liste[1])
print(tupel[2])
# Element an Liste anhängen und einfügen
liste.append(55)
liste.insert(4, "Welt")
print(liste)
# Element aus Liste entfernen
liste.remove(1)
print(liste)
# einige weitere Beispiele
liste2 = [1,]
tupel2 = 1, 2
tupel3 = (1,)
print(liste2)
print(tupel2)
print(tupel3)
Ausgabe:
[1, 2, 'Hallo']
(1, 2, 'Hallo')
2
Hallo
[1, 2, 'Hallo', 55, 'Welt']
[2, 'Hallo', 55, 'Welt']
[1]
(1, 2)
(1,)
Beispiel (eine Liste von Wörtern zu einem einzigen zusammenhängenden Text verbinden):
woerter = ["Hallo", "Welt"]
satz = " ".join(woerter)
print(satz)
Ausgabe:
Hallo Welt
== Dictionaries und Mengen ==
Zu den Datenstrukturen gehören weiters auch Mengen und Dictionaries. Mengen sind von der Mathematik bekannt, sie sind ungeordnet und es kommen keine mehrfachen Elemente vor. Dictionaries sind durch Schlüssel :Wert-Paare gekennzeichnet. Mengen werden beim Anlegen wie Dictionaries in geschweifte Klammern eingeschlossen.
dict = {"vorname":"Hugo", "nachname":"Meister" }
menge = {1, 1, 3, 4, 4, 4, "Hallo"}
print(dict)
print(menge)
print(dict["vorname"])
Ausgabe:
{'vorname': 'Hugo', 'nachname': 'Meister'}
{1, 3, 4, 'Hallo'}
Hugo
Geschweifte Klammern ohne Inhalt stellen Dictionaries dar und keine Mengen:
di = {}
print(type(di))
Ausgabe:
<class 'dict'>
Leere Mengen lassen sich mit <code>set()</code> erzeugen:
menge = set() # leere Menge
print(menge)
menge.add("Hallo") # Element hinzufügen
print(menge)
Ausgabe:
set()
{'Hallo'}
Beispiel (einige Mengenoperationen):
mengeA = {"Hallo", "Welt"}
mengeB = {1, 2, "Welt", 3}
# Vereinigung
print(mengeA | mengeB)
print(mengeA.union(mengeB))
# Durchschnitt
print(mengeA & mengeB)
print(mengeA.intersection(mengeB))
# Differenz
print(mengeA - mengeB)
print(mengeA.difference(mengeB))
# Symmetrische Differenz
print(mengeA ^ mengeB)
print(mengeA.symmetric_difference(mengeB))
# Teilmenge
print(mengeA.issubset(mengeB))
# Mehrere Elemente hinzu
mengeA.update(["Super", 67, 125])
print(mengeA)
# Element löschen
mengeA.discard("Hallo")
print(mengeA)
Ausgabe:
{1, 2, 3, 'Welt', 'Hallo'}
{1, 2, 3, 'Welt', 'Hallo'}
{'Welt'}
{'Welt'}
{'Hallo'}
{'Hallo'}
{1, 2, 3, 'Hallo'}
{1, 2, 3, 'Hallo'}
False
{67, 'Super', 'Welt', 'Hallo', 125}
{67, 'Super', 'Welt', 125}
== List Comprehensions ==
Aus einer Eingabeliste soll eine Ausgabeliste erzeugt werden. Das kann folgendermaßen geschehen.
Mathematische Schreibweise: <math>lc = \{2x|x\in\ \mathbb{N}, 1\le x < 11\}</math>
Python-Code:
lc = [x*2 for x in range(1,11)]
print(lc)
Ausgabe:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
Mathematische Schreibweise: <math>lc = \{2x | x \in \mathbb{N}, 1\le x < 11, x \bmod 2 = 0 \}</math>
Python-Code:
lc = [x*2 for x in range(1,11) if x%2 == 0]
print(lc)
Ausgabe:
[4, 8, 12, 16, 20]
Siehe auch {{W|List Comprehension}}.
== Set Comprehensions ==
Dies ist sehr ähnlich wie im vorigen Abschnitt beschrieben. Es wird aber keine Liste, sondern eine Menge erzeugt.
sc = {x*2 for x in range(1,11)}
print(sc)
Ausgabe:
{2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
== Listen zusammenführen - zip() ==
li1 = ["A", "B", "C", "D"]
li2 = [1, 2, 3, 4]
li3 = [5.5, 6.6, 7.7, 8.8]
z = zip(li1, li2, li3)
print(z)
li4 = list(z)
print(li4)
Ausgabe:
<zip object at 0x00000283B6C6AC80>
[('A', 1, 5.5), ('B', 2, 6.6), ('C', 3, 7.7), ('D', 4, 8.8)]
== Generatorausdruck ==
g = (i*2 for i in range(1,11))
print(g)
t = tuple(g)
print(t)
print(t[1:3])
Ausgabe:
<generator object <genexpr> at 0x00000241D2A4A5A0>
(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
(4, 6)
== Slicing ==
slice ... Scheibe, Teil, in Scheiben schneiden
Beispiel: Zugriff auf Elemente eines geordneten sequentiellen Objekttyps (Liste, Tupel oder String):
str1 = "Hallo"
# Das erste Element wird mit dem Index 0 angesprochen
# [start (inkl.) : stop (exkl.) : step (default=1)]
str2 = str1[0:2]
# Alternativ auch: str2 = str1[:2]
print(str2)
tup1 = (0,1,2,3)
# Das letzte Element hat auch den Index -1, das vorletzte den Index -2 usw.
tup2 = tup1[-3:-1]
print(tup2)
lst1 = [[1, 5, 10, 20],
[30, 40, 50, 60]]
lst2 = lst1[1][1]
print(lst2)
Ausgabe:
Ha
(1, 2)
40
Beispiel: Umdrehen von Strings
str1 = "Hallo"
str2 = str1[::-1]
print(str2)
Ausgabe:
ollaH
= Objektorientierte Programmierung =
{{Wikipedia|Objektorientierte Programmierung}}
* {{W|Klasse (Objektorientierung)|Klasse}} ... die Schablone oder der Bauplan, enthält Methoden und Attribute
* {{W|Objekt (Programmierung)|Objekt}} ... eine Klasseninstanz (die konkrete Ausprägung der Klasse)
* {{W|Attribut (Programmierung)|Attribute}} ... die Eigenschaften eines Objekts
* {{W|Methode (Programmierung)|Methoden}} ... die Aktionen (Operationen), die ein Objekt ausführen kann
* {{W|Vererbung (Programmierung)|Vererbung}} ... neue Klassen (Subklassen, Unterklassen, abgeleitete Klassen) aus vorhandenen Klassen (Superklassen, Oberklassen, Basisklassen, Elternklassen) ableiten. Ermöglicht den Aufbau von Klassenhierarchien. Die Subklasse "erbt" Attribute und Methoden von der Superklasse. Python unterstützt (so wie C++, aber im Gegensatz zu Java) Mehrfachvererbung.
== UML ==
* {{W|Unified Modeling Language|UML}} ... '''U'''nified '''M'''odeling '''L'''anguage, eine Modellierungssprache. Die UML enthält zahlreiche Diagrammarten, um Programme zu modellieren. Im Nachfolgenden wird nur das {{W|Klassendiagramm}} verwendet.
[[File:UmlCd Klasse-3.svg|300px]]
* {{W|Sichtbarkeit (Programmierung)|Sichtbarkeit}}:
** + ... public (öffentlich)
** - ... private
** # ... protected
* {{W|Attribut_(UML)#Attribute_für_Instanzen_und_für_Klassen|Klassenattribute}} (statische Attribute): Werden nur einmal pro Klasse angelegt. Im Klassendiagramm werden sie unterstrichen.
[[File:Attribute-3.png|200px]]
* Vererbung:
<gallery>
InheritancePgmUML.svg | Abgeleitete Klasse erbt von Basisklasse (Einfachvererbung)
Diamond inheritance.svg | D erbt von B und C (Mehrfachvererbung). B und C erben von A (Einfachvererbung)
</gallery>
Für weitergehende Betrachtungen zur UML wird auf Spezialliteratur verwiesen, z.B.:
* Seidl et al.: UML@Classroom. dpunkt, 2012, ISBN 978-3-89864-776-2
* Rupp et al.: UML 2 glasklar. Hanser, 4. Aufl., 2012, ISBN 978-3-446-43057-0
== Eine einfache Klasse ==
[[Datei:PythonIng_uml1.svg | 200px]]
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
fahr = Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die Klasse Fahrzeug wird durch das class-Schlüsselwort eingeleitet. raeder ist ein Klassenattribut und public. __init__ wird bei der Objekterzeugung automatisch aufgerufen (ist der sogenannte Konstruktor). Man achte darauf, dass diese Methode immer mit zwei Unterstrichen eingeleitet und abgeschlossen wird. Instanzattributen wird das Wort self vorangestellt. Wir sehen uns z.B. das Attribut self.__geschwind an. Auch hier werden zwei Unterstriche verwendet. Das bedeutet, dass dieses Attribut strikt/stark private ist. Wird nur ein Unterstrich verwendet, so deutet dies auf schwach/weakly private hin. Letzteres wird in Python deutlich häufiger verwendet. Bei den Methoden wird immer self als erster Parameter angegeben. Beim Aufruf der entsprechenden Funktion wird das self aber nicht berücksichtigt.
Besonderheiten bei stark und schwach private:
* '''stark private''':
** zwei führende Unterstriche
** Name Mangling: Name wird zu <code>_Klassenname__variablenname</code>
** Schutz vor Namenskollisionen bei Vererbung
** am Ende des Namens dürfen keine zwei Unterstriche verwendet werden. Das wären dann Magic Methods oder Dunder-Methods (z.B. __init__). Diese sind public.
* '''schwach private''':
** ein führender Unterstrich
** Name bleibt gleich
** ist nur ein Hinweis an die Programmierer, kein starker Schutz
** <code>from modul import *</code>: Objekte mit einem führenden Unterstrich werden standardmäßig nicht importiert
** Standard für die Kapselung bei Python. Schätzung: Weit mehr als 80% der nicht-öffentlichen Attribute/Methoden werden als schwach private deklariert. Weniger als 5-10% als stark private (Quelle: Google KI)
== Klassen importieren ==
Häufig ist es sinnvoll und übersichtlicher Klassen in eigenen Dateien zu speichern. Das sind dann eigene Module. Abgespeichert werden Sie mit der Endung py, wie bisher auch praktiziert. Aufgerufen werden Sie mit der import-Anweisung. Dann ist aber nur der Dateiname ohne Endung py zu verwenden. Klarer wird das mit einem Beispiel.
Datei c:\tmp\fahrzeug.py
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
Datei c:\tmp\test1.py
import fahrzeug
fahr = fahrzeug.Fahrzeug(150, 90)
print(fahr.convertGeschw())
Ausgabe:
41.666666666666664
Die üblichen import-Anweisungen lauten wie folgt:
{| {{prettytable}}
! import-Befehl
! Instanz
|-
| import xyz || xyz.Klasse
|-
| import xyz as x || x.Klasse
|-
| from xyz import Klasse || Klasse
|-
| from xyz import * || Klasse
|}
Der Vorteil der ersten beiden import-Anweisungen ist, dass es kaum zu Namenskollisionen kommen kann. Dafür hat man bei den letzten beiden Varianten weniger Tipparbeit.
== Vererbung ==
=== Einfachvererbung ===
[[Datei:PythonIng_uml2.svg | 200px]]
Datei fahrzeug.py:
class Fahrzeug:
raeder = 4
def __init__(self, geschwindigkeit, leistung):
self.__geschwind = geschwindigkeit
self.__leistung = leistung
def setGeschwindigkeit(self, geschwindigkeit): # geschwindigkeit in km/h
self.__geschwind = geschwindigkeit
def setLeistung(self, leistung):
self.__leistung = leistung
def convertGeschw(self):
# geschwindigkeit in m/s rueckgeben
return self.__geschwind / 3.6
class Luftfahrzeug(Fahrzeug):
def __init__(self, geschwindigkeit, leistung, fluegel):
super().__init__(geschwindigkeit, leistung)
self.__flueg = fluegel
def getFlueg(self):
return self.__flueg
Datei test1.py:
import fahrzeug
fahr = fahrzeug.Luftfahrzeug(150, 90, 4)
print(fahr.getFlueg())
Ausgabe:
4
=== Mehrfachvererbung ===
Mit Python ist auch Mehrfachvererbung möglich, z.B.:
class A:
def _printA(self):
print("Klasse A")
class B:
def _printB(self):
print("Klasse B")
class C(A,B):
def __init__(self):
self._printA()
self._printB()
c = C()
Ausgabe:
Klasse A
Klasse B
Die Klasse C erbt von A und B. In UML sieht das in etwa so aus:
+-----------------------------+ +-------------------------+
| A | | B |
+-----------------------------+ +-------------------------+
| | | |
+-----------------------------+ +-------------------------+
| # printA() | | # printB() |
+-----------------------------+ +-------------------------+
. .
/ \ / \
--- ---
| |
| |
+---------------------+
| C |
+---------------------+
| |
+---------------------+
| |
+---------------------+
<code>printA()</code> und <code>printB()</code> sind schwach private (in UML als <code>protected</code> mit einem # dargestellt). Es ist aber zu beachten, dass schwach private nur Konvention ist. Praktisch könnte man auch von außerhalb auf diese Methoden zugreifen. Das soll man aber nicht tun, und das wird in Python durch einen Unterstrich angedeutet.
= Grafiken zeichnen =
Für das Zeichnen von Grafiken wird hier das Modul <code>matplotlib</code> verwendet. <code>matplotlib</code> ist ein externes Modul und muss vor der ersten Verwendung installiert werden. Das geht so:
# Starten Sie ein Terminal (bei Windows die Eingabeaufforderung).
# Führen Sie darin folgenden Befehl aus <code>c:\devel\Python\Scripts\pip.exe install matplotlib</code>
pip ist übrigens der Paketmanager von Python ({{W|Pip_(Python)}}).
Optimalerweise installieren wir auch gleich das Modul <code>numpy</code> (Numerical Python). Wir werden es im Folgenden oft benötigen (nicht nur bei den Grafiken). Das funktioniert vom Prinzip her genauso, wie für <code>matplotlib</code> gezeigt.
<small>Verwenden Sie Spyder, so sind diese Schritte nicht nötig. Spyder inkludiert diese Pakete standardmäßig. Unter openSUSE Tumbleweed lassen sich diese Pakete mittels YaST oder zypper installieren.</small>
== 2D ==
=== Graph einer Funktion ===
Es soll die cosh-Funktion im Intervall <math>x\in[-3,3]</math> gezeichnet werden. Der Programmcode lautet in der einfachsten Form:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x)
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh1.jpg]]
Der Code ist quasi selbsterklärend. Das Untermodul pyplot des matplotlib-Moduls und das numpy-Modul werden importiert. x läuft von -3 bis +3. y wird für jeden x-Wert per Formel ausgerechnet. "plt.plot()" ist der Zeichenbefehl. "plt.show" ist notwendig, um das Fenster mit der Grafik anzuzeigen.
Die Schrittweite 0.1 wurde so gewählt, um einen ausreichend glatten Verlauf des Graphen zu gewährleisten. Das ist immer ein Kompromiss zwischen Berechnungszeit und Ansehnlichkeit. Testen Sie einfach ein paar verschiedene Werte, um ein Gefühl dafür zu zu bekommen. "plt.grid()" zeichnet ein Gitter in die Grafik (kann auch weggelassen werden).
Die Bezeichnungen plt und np könnten auch anders gewählt werden. Es ist aber Konvention, diese so wie hier gezeigt zu wählen.
<small>Mit der im obigen Bild gezeigten Menüleiste kann die dargestellte Grafik nachträglich noch geändert werden (Zoom, Pan, Achsenparameter, Kurvenparameter etc.). Natürlich kann man das alles auch direkt programmieren. Wie das funktioniert wird ansatzweise etwas später gezeigt.</small>
Ein etwas komplexeres Beispiel ist Folgendes:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y = np.cosh(x) + 2**x
plt.plot(x,y)
plt.grid()
plt.show()
Ausgabe:
[[Datei:PythonIng_cosh4.png]]
Man beachte, dass im Gegensatz zu Octave und Julia der ominöse Punkt (.) bei 2**x mit Python nicht benötigt wird. Das macht das Programmiererleben etwas einfacher.
=== Graphen mehrerer Funktionen und weiteres ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x")
plt.plot(x, y2, label = "sin(x) * cos(x)")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh2.png]]
Um die Linienstile etwas individueller zu gestalten, ist folgender Programmcode gedacht:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(-3., 3.1, .1)
y1 = np.cosh(x) + 2**x
y2 = np.sin(x) * np.cos(x)
plt.plot(x, y1, label = "cosh(x) + 2**x", lw=5, ls="dotted")
plt.plot(x, y2, label = "sin(x) * cos(x)", lw=3, ls="--")
plt.grid()
plt.title("Funktionsgraphen")
plt.xlabel("x")
plt.ylabel("y")
plt.legend(loc="best")
plt.show()
[[Datei:PythonIng_cosh3.png]]
=== Funktion in Parameterdarstellung ===
Es soll die archimedische Spirale <math>x = t \cos(t), y = t \sin(t)</math> im Intervall <math>[0, 6\pi[</math> gezeichnet werden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.show()
[[Datei:PythonIng_spirale1.png]]
Diese Darstellung erscheint verzerrt. Will man gleiche Achsenskalierungen, so kann man den plt.axis()-Befehl verwenden.
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0., 6*np.pi, .1)
x = t * np.cos(t)
y = t * np.sin(t)
plt.plot(x, y)
plt.grid()
plt.title("Archimedische Spirale")
plt.axis("equal")
plt.show()
[[Datei:PythonIng_spirale2.png]]
=== Funktion in Polardarstellung ===
import matplotlib.pyplot as plt
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(projection="polar")
r = np.arange(0, 1, 0.01)
theta = r**3
line = ax.plot(theta, r)
plt.show()
[[Datei:PythonIng_polar1.png]]
=== Logarithmische Achsenskalierung ===
==== Semilog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.semilogy()
plt.show()
Ausgabe:
[[Datei:PythonIng_semilog1.png]]
==== LogLog ====
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0., 10, .1)
y = 10**x
plt.plot(x, y)
plt.grid()
plt.loglog()
plt.show()
[[Datei:PythonIng_loglog1.png]]
=== Gefüllte Fläche ===
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(0, 3, 0.1)
y1 = 3*x - 1
y2 = x**2
plt.plot(x, y1, x, y2, color='black')
plt.fill_between(x, y1, y2, where=y1>=y2)
plt.show()
[[Datei:PythonIng_gefuellt.png]]
=== Linien, Pfeile, Rechtecke, Kreise und Texte ===
import matplotlib as mpl
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
r = mpl.patches.Rectangle((0, 0), 3, 3, angle=30, fill=False)
c = mpl.patches.Circle((4, 4), 2, fill=False)
ax.add_patch(r)
ax.add_patch(c)
ax.plot([-2, 7], [-2, 0], color="black")
ax.arrow(0, 7, 5, 0, length_includes_head=True, head_width=0.5, head_length=1.5,
color="black")
ax.set_aspect("equal")
plt.axis([-3, 8, -3, 8])
plt.show()
[[Datei:PythonIng_linien_pfeile_etc.png]]
Text kann mit <code>ax.text(x, y, "Text")</code> hinzugefügt werden, bspw.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.text(0.1, 0.1, "Hallo")
ax.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
Oder einfacher auch ohne <code>subplots</code>
import matplotlib.pyplot as plt
plt.text(0.1, 0.1, "Hallo")
plt.text(0.5, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text1.png]]
Auch Sonderzeichen (griechische Buchstaben etc.) können verwendet werden (siehe dazu auch [https://matplotlib.org/stable/users/explain/text/mathtext.html]).
import matplotlib.pyplot as plt
plt.text(.3, .5,
r'$\Omega\ \psi\ \oint\ \nabla\ \dot a\ \frac{a}{b}\ a_b$',
size="20")
plt.show()
[[Datei:PythonIng_text20.svg]]
Jetzt wird noch gezeigt, wofür <code>subplots</code> sinnvoll eingesetzt werden können.
import matplotlib.pyplot as plt
fig, ax = plt.subplots(nrows=1, ncols=2)
ax[0].text(0.1, 0.1, "Hallo")
ax[1].text(0.1, 0.5, "Welt", size="40", family="cursive", style="italic",
rotation=30.0)
plt.show()
[[Datei:PythonIng_text2.png]]
=== Aufgaben ===
* Zeichnen Sie die Strophoide <math>x = \frac{a(t^2-1)}{t^2+1}, y = \frac{at(t^2-1)}{t^2+1}, a = 2, -3 \leq t \leq 3</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_strophoide.jpg]]
* Zeichnen Sie die verschlungene Hypozykloide <math>x = (R-r)\cos t + c\cos\frac{R-r}{r}t, y = (R-r)\sin t - c\sin\frac{R-r}{r}t, c = 3, r = 2, R = 6, -15 \leq t \leq 15</math>. Das Ganze sollte in etwa so aussehen wie folgende Grafik:
[[Datei:octave_hypozykloide.jpg]]
* Testen Sie bei den obigen Übungsaufgaben verschiedene Linienstile und Farben. Farben können mit dem plt.plot()-Parameter color gewählt werden.
* Testen Sie bei den obigen Übungsaufgaben verschiedene Werte für a, c, r und R.
== 3D ==
=== Räumliche Kurven ===
import matplotlib.pyplot as plt
import numpy as np
t = np.arange(0, 6*np.pi, 0.1)
x = t * np.cos(t)
y = t * np.sin(t)
z = t
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot(x, y, z)
plt.show()
[[Datei:PythonIng_raumkurve1.png]]
=== Flächen ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z)
plt.show()
[[Datei:PythonIng_fläche1.png]]
Das Ganze in Netzdarstellung läßt sich so programmieren:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.5)
y = np.arange(0, 10, 0.5)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_wireframe(x, y, z)
plt.show()
[[Datei:PythonIng_fläche2.png]]
Ein etwas komplexeres Beispiel:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0.1, 10, 0.1)
y = np.arange(0.1, 10, 0.1)
x, y = np.meshgrid(x, y)
z1 = np.sin(x) + 3 * np.cos(y)
z2 = np.sin(x) + np.log(y)
z3 = x + np.cos(y)
z4 = x**2 - y
fig, ax = plt.subplots(subplot_kw={"projection": "3d"}, nrows=2, ncols=2)
ax[0][0].plot_surface(x, y, z1)
ax[0][1].plot_surface(x, y, z2)
ax[1][0].plot_surface(x, y, z3)
ax[1][1].plot_surface(x, y, z4)
plt.show()
[[Datei:PythonIng_subplot1.png]]
Man beachte, dass man die Unterbilder im Bild nach dem Ausführen des Scripts z.B. mit der mittleren Maustaste einzeln drehen, oder über die Einträge in der Menüzeile einzeln bearbeiten kann. Mit ein paar Zeilen Programmtext lässt sich also eine Menge an Funktionalität generieren.
Die Farbgebung lässt sich über <code>colormaps</code> variieren.
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm)
plt.show()
[[Datei:PythonIng_colormap1.png]]
Es gibt eine Menge an Colormaps, z.B. <code>plasma, Greys, Dark2, ocean</code>. Zwecks detaillierterer Infos siehe die matplotlib-Dokumentation. <small>Verwendet man die IDE namens IDLE, so gibt es dort auch die automatische Codevervollständigung. D.h. es werden alle Möglichkeiten (in unserem Fall nach dem Eintippen von <code>cm.</code> alle verfügbaren Colormaps) angezeigt.</small>
Die "edgecolor" und Linienbreite können auch frei gewählt werden:
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import cm
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots(subplot_kw={"projection": "3d"})
ax.plot_surface(x, y, z, cmap = cm.coolwarm, edgecolor="black", linewidth=1.0)
plt.show()
[[Datei:PythonIng_colormap2.png]]
=== Höhenlinien ===
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
ax.contour(x, y, z)
plt.show()
[[Datei:PythonIng_höhenlinien1.png|400px]]
Etwas abgewandelt sieht das so aus:
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contour(x, y, z)
ax.clabel(hl, inline = True)
plt.show()
[[Datei:PythonIng_höhenlinien2.png|400px]]
Und noch eine Variante (mit einem Farbbalken) sei gezeigt.
import matplotlib.pyplot as plt
import numpy as np
x = np.arange(0, 10, 0.1)
y = np.arange(0, 10, 0.1)
x, y = np.meshgrid(x, y)
z = np.sin(x) + 3 * np.cos(y)
fig, ax = plt.subplots()
hl = ax.contourf(x, y, z)
fig.colorbar(hl)
plt.show()
[[Datei:PythonIng_höhenlinien5.svg|400px]]
=== Aufgaben ===
* Zeichnen Sie die räumliche Kurve <math>x = 2 \cdot \cosh(t)</math>, <math>y = 5 \cdot \sin(t)</math>, <math> z = t^{2} - t</math>, <math>0 \leq t \leq 3\pi</math>.
* Zeichnen Sie die Fläche <math>z = \log(x) + \cos(y)</math>.
== Animationen ==
=== Mit matplotlib ===
Auch mit matplotlib sind Animationen möglich. Das ist ein bisschen komplizierter und wird deshalb hier nur mit einem sehr einfachen Beispiel dargestellt (bei Interesse siehe z.B. auch das [https://matplotlib.org/stable/users/explain/animations/animations.html#animations Animations using Matplotlib-Tutorial]).
import matplotlib.pyplot as plt
import matplotlib.animation as ani
import matplotlib
import numpy as np
def update(frame):
line.set_xdata(x[:frame])
line.set_ydata(y[:frame])
return (line)
fig, ax = plt.subplots()
x = np.arange(0, 10, .1)
y = np.sin(x)
line, = ax.plot(x[0], y[0])
ax.set(xlim=[0, 10], ylim=[-1, 1])
a = ani.FuncAnimation(fig=fig, func=update, frames=100, interval=20)
plt.show()
# Speichere die Animation in einem animierten GIF (optional)
a.save(filename="c:/tmp/PythonIng_anim5.gif", writer="pillow")
[[Datei:PythonIng_anim5.gif]]
Es wird eine Sinuskurve auf den Bildschirm gezeichnet. In der letzten Zeile wird diese Animation in ein animiertes GIF gespeichert. Das ist natürlich optional und kann auch weggelassen werden.
=== Mit VPython ===
Aber auch mit dem Modul VPython lassen sich einfache 3D-Animationen erstellen. VPython ist ein externes Modul, das vorab installiert werden muss. Unter openSUSE Tumbleweed gibt es dzt. kein entsprechendes rpm-Paket. Die übliche Methode der Installation mittels YaST oder zypper ist somit nicht möglich. Auch eine direkte Verwendung von pip führt nur zu einer Fehlermeldung (<code>error: externally-managed-environment</code>). Es empfiehlt sich dort folgende Vorgehensweise:
# Erstelle zuerst eine virtuelle Umgebung, z.B.: <code>python3.11 -m venv ~/tmp/venv1</code>
# Wechsle das Verzeichnis: <code>cd ~/tmp/venv1/bin</code>
# Installiere das entsprechende Paket: <code>./pip install vpython</code>
# Führe das entsprechende Skript aus: <code>./python ~/tmp/test1.py</code>
Aktuell (März 2026) ist dieses Programmpaket lt. der [https://vpython.org/presentation2018/install.html VPython-Homepage] nur für die Python-Versionen 3.8 bis 3.12 verfügbar.
Ein Beispiel zu einer einfachen Animation wird nachfolgend geliefert.
from vpython import *
scene.width = 1200
scene.height = 600
scene.center = vector(20,0,0)
scene.background = color.white
cylinder(pos=vector(0,0,0), axis=vector(20,0,0), radius=5,
color=color.blue)
cone(pos=vector(0,0,0), axis=vector(-10,0,0), radius=5,
color=color.blue)
helix(pos=vector(20,0,0), axis=vector(40,0,0), radius=2,
coils=10, thickness=0.5, color=color.blue)
ball = sphere(pos=vector(20,0,0), color = color.green, radius = 1)
ball.p = vector(0.15, 0, 0)
toc = True
while True:
rate(200)
if(ball.pos.x <= 60 and toc == True):
ball.pos += ball.p
else:
toc = False
ball.pos -= ball.p
if(ball.pos.x <= 20 and toc == False):
toc = True
[[Datei:PythonIng_vpython_anim.JPG]]
Idealerweise öffnet sich beim Ausführen des Scripts ein Browserfenster. Darin wird die programmierte Animation gezeigt (siehe auch den obigen Screenshot). Eine Größenänderung können Sie mit der mittleren Maustaste initiieren. Die Szenerie drehen können Sie mit der rechten Maustaste.
=== Mit VTK ===
Komplexer, aber auch mächtiger als VPython ist die Verwendung von VTK ('''V'''isualization '''T'''ool'''k'''it). Genauer gesagt des Python-Wrappers von VTK. Dieses externe Python-Modul muss vorab installiert werden (z.B. mittels YaST, pip oder in eine virtuelle Umgebung). VTK ist eine Softwarebibliothek zur 3D-Visualisierung und wurde ursprünglich in C++ geschrieben. Verbreitet eingesetzt wird diese Bibliothek in der Wissenschaft und Forschung, z.B.
* in der medizinischen Bildgebung
* für Strömungssimulationen
* für Klimadaten
VTK funktioniert nach dem {{W|Grafikpipeline|Pipeline-Prinzip}}:
Source (Quellen) -> Filter -> Mapper (Senken) -> Actor/Renderer
Daten fließen von den Quellen zu den Senken.
Als einfaches Beispiel wird die Darstellung eines Zylinders gezeigt, der mit den Maustasten gedreht oder in der Größe geändert werden kann:
import vtk
# Zylinder erzeugen
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
# Geometrie in darstellbare Daten umwandeln
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
# Objekt in der Szene
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# Szene verwalten
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
# Render-Fenster
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
# Maus/Tastatur-Steuerung
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# Starten
render_window.Render()
interactor.Start()
Ausgabe:
[[Datei:PythonIng_VTK_1.png]]
Gleiches Beispiel wie oben, aber mit einer Animationssequenz:
import vtk
import time
cyl = vtk.vtkCylinderSource()
cyl.SetRadius(5.0)
cyl.SetHeight(20.0)
cyl.SetResolution(40)
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cyl.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
renderer = vtk.vtkRenderer()
renderer.AddActor(actor)
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
render_window.Render()
time.sleep(0.01)
Das Grafikfenster schließt sich nach Ablauf der Schleife. Das Fenster bleibt geöffnet, wenn Sie am Programmende folgenden Befehl hinschreiben
interactor.Start()
Um den animierten Zylinder grün einzufärben, müssen Sie Folgendes im obigen Programm ergänzen (Farbnamen):
colors = vtk.vtkNamedColors()
actor.GetProperty().SetColor(colors.GetColor3d("Green"))
Als Namen können Sie u.a. die CSS3 Web-Farben verwenden (siehe z.B. [https://wiki.selfhtml.org/wiki/Farbe/Farbangaben] und {{W|Webfarbe#CSS_3}}).
Alternativ funktioniert auch das ({{W|RGB-Farbraum|RGB}}):
actor.GetProperty().SetColor(0.0, 0.6, 0.0)
Wie der Zylinder mit einer Textur versehen wird, zeigt folgendes Programm:
import vtk
import time
cylinder = vtk.vtkCylinderSource()
cylinder.SetResolution(30)
cylinder.SetHeight(3.0)
cylinder.SetRadius(1.0)
cylinder.CappingOn()
texture_coords = vtk.vtkTextureMapToCylinder()
texture_coords.SetInputConnection(cylinder.GetOutputPort())
texture_coords.PreventSeamOn()
reader = vtk.vtkJPEGReader()
reader.SetFileName("PythonIng_textur.jpg")
texture = vtk.vtkTexture()
texture.SetInputConnection(reader.GetOutputPort())
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(texture_coords.GetOutputPort())
actor = vtk.vtkActor()
actor.SetMapper(mapper)
actor.SetTexture(texture)
renderer = vtk.vtkRenderer()
renderWindow = vtk.vtkRenderWindow()
renderWindow.AddRenderer(renderer)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
for i in range(360):
actor.RotateZ(1)
actor.RotateY(.5)
renderWindow.Render()
time.sleep(0.01)
interactor.Start()
<gallery>
PythonIng_textur.jpg | Textur-Datei
PythonIng_VTK_2.png | Ausgabe (Screenshot)
</gallery>
Nun aber genug von VTK und der Erstellung von Grafiken, weiter geht es mit mathematischeren Themen.
= Vektoren und Matrizen =
== Zahlenfolgen ==
Für das Erstellen von Zahlenfolgen bieten sich die Funktionen <code>arange</code> und <code>linspace</code> aus dem <code>numpy</code>-Modul an.
from numpy import *
start = 0
stop = 10
step = 2
num = 10
r = arange(start, stop, step) # step ... Schrittweite
l = linspace(start, stop, num) # num ... Anzahl der Werte
print("r = ", r)
print("l = ", l)
Ausgabe:
r = [0 2 4 6 8]
l = [ 0. 1.11111111 2.22222222 3.33333333 4.44444444 5.55555556
6.66666667 7.77777778 8.88888889 10. ]
Bei <code>arange</code> ist der <code>stop</code>-Wert nicht im Ergebnis enthalten, bei <code>linspace</code> aber sehr wohl.
== Vektoren ==
Vektoren sollten jedem aus der Linearen Algebra bekannt sein.
=== Arrays ===
In Python mit NumPy kann man Vektoren durch die Funktion array erzeugen.
import numpy as np
l1 = (-5, 3, 2)
l2 = (1, 1, 4)
a1 = np.array(l1)
a2 = np.array(l2)
a3 = a1 + a2
a4 = 2 * a2
print(a1)
print(a2)
print(a3)
print(a3[2])
print(a4)
Ausgabe:
[-5 3 2]
[1 1 4]
[-4 4 6]
6
[2 2 8]
=== Zeilen- und Spaltenvektoren ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
print(z)
print(s)
Ausgabe:
[ [-5 3 2] ]
[[1]
[1]
[4]]
=== Skalarprodukt ===
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
skalarprodukt = np.dot(a1, a2)
print(skalarprodukt)
Ausgabe:
6
=== Vektorprodukt ===
<math>a\ast b=\left(\begin{array}{c}
a_{1}\\
a_{2}\\
a_{3}
\end{array}\right)\ast\left(\begin{array}{c}
b_{1}\\
b_{2}\\
b_{3}
\end{array}\right)=\left(\begin{array}{c}
a_{2}b_{3}-a_{3}b_{2}\\
a_{3}b_{1}-a_{1}b_{3}\\
a_{1}b_{2}-a_{2}b_{1}
\end{array}\right)
</math>
Python-Code:
import numpy as np
a1 = np.array((-5, 3, 2))
a2 = np.array((1, 1, 4))
vektorprodukt = np.cross(a1, a2)
print(vektorprodukt)
Ausgabe:
[10 22 -8]
=== Transponierter Vektor ===
import numpy as np
# Zeilenvektor
z = np.array([ [-5, 3, 2] ])
# Spaltenvektor
s = np.array([[1], [1], [4]])
# transponierter Vektor
z_tp = np.transpose(z)
# transponierter Vektor
s_tp = np.transpose(s)
print(z_tp)
print(s_tp)
Ausgabe:
[[-5]
[ 3]
[ 2]]
[ [1 1 4] ]
=== Vektorfelder visualisieren ===
import matplotlib.pyplot as plt
import numpy as np
# Daten generieren
x = np.arange(0, 10, 1)
y = np.arange(0, 10, 1)
X, Y = np.meshgrid(x, y)
U = X * Y
V = Y + X
# Plotten
fig, ax = plt.subplots()
ax.quiver(X, Y, U, V, angles='xy')
plt.show()
Ausgabe:
[[Datei:PythonIng_quiver1.png]]
== Matrizen==
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
print(m1)
Ausgabe:
[[1 2 3]
[4 5 6]]
=== Zugriff auf Matrizenelemente ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
# Element aus Zeile 2 und Spalte 3 (Achtung! Index startet bei Null)
print(m1[1,2])
Ausgabe:
6
=== Addition und Subtraktion von Matrizen ===
import numpy as np
m1 = np.matrix([[1, 2, 3], [4, 5, 6]])
m2 = np.matrix([[0, 0, 2], [1, 3, 2]])
print(m1 + m2)
print(m1 - m2)
Ausgabe:
[[1 2 5]
[5 8 8]]
[[1 2 1]
[3 2 4]]
=== Transponierte Matrix ===
import numpy as np
m = np.matrix([[1, 2, 3], [4, 5, 6]])
mt = np.transpose(m)
print(m)
print(mt)
Ausgabe:
[[1 2 3]
[4 5 6]]
[[1 4]
[2 5]
[3 6]]
=== Rang einer Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
rg = np.linalg.matrix_rank(m)
print(rg)
Ausgabe:
2
=== Inverse Matrix ===
import numpy as np
m = np.matrix([[1, 3], [0, -5]])
mi = np.linalg.inv(m)
print(mi)
Ausgabe:
[[ 1. 0.6]
[-0. -0.2]]
=== Multiplikation von Matrizen (falksches Schema) ===
import numpy as np
m1 = np.matrix([[1, 3, 4], [0, -5, 1]])
m2 = np.matrix([[1, 2], [2, 3], [0, 2]])
print(m1 @ m2)
Ausgabe:
[[ 7 19]
[-10 -13]]
=== Eigenwerte und Eigenvektoren ===
import numpy as np
m = np.matrix([[5, 8], [1, 3]])
D,V = np.linalg.eig(m)
# Eigenwerte
print(D)
# Eigenvektoren
print(V)
Ausgabe:
[7. 1.]
[[ 0.9701425 -0.89442719]
[ 0.24253563 0.4472136 ]]
=== Teilmatrizen ===
import numpy as np
m = np.matrix([[1, 3, 4], [0, -5, 1]])
print("m = ", m)
# Erste Zeile extrahieren
m1 = m[0,:]
print("m1 = ", m1)
# Das Element aus der 1. Zeile und der 2. Spalte extrahieren
m2 = m[0,1]
print("m2 = ", m2)
# Zweite Spalte extrahieren
m3 = m[:, 1]
print("m3 = ", m3)
Ausgabe:
m = [[ 1 3 4]
[ 0 -5 1]]
m1 = [ [1 3 4] ]
m2 = 3
m3 = [[ 3]
[-5]]
=== Spezielle Matrizen ===
==== Nullmatrix ====
import numpy as np
z = np.zeros((3, 2))
print(z)
Ausgabe:
[[0. 0.]
[0. 0.]
[0. 0.]]
==== Einheitsmatrix ====
import numpy as np
z = np.eye(3)
print(z)
Ausgabe:
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
==== Matrix mit lauter Einsen ====
import numpy as np
z = np.ones((3, 2))
print(z)
Ausgabe:
[[1. 1.]
[1. 1.]
[1. 1.]]
=== Spärlich besetzte Matrizen ===
Das Thema spärlich besetzter Matrizen wird hier nur kurz angerissen. Nähere Details siehe unter dem Weblink [https://docs.scipy.org/doc/scipy/reference/sparse.html#module-scipy.sparse].
import numpy as np
import scipy
A = scipy.sparse.csr_array(np.eye(5))
print(A)
Ausgabe:
(0, 0) 1.0
(1, 1) 1.0
(2, 2) 1.0
(3, 3) 1.0
(4, 4) 1.0
= Lineare Gleichungssysteme =
Sei <math>Ax = b</math> ein lineares Gleichungssystem. <math>A</math> sei die Koeffizientenmatrix, <math>x</math> der Lösungsvektor und <math>b</math> ein bekannter Vektor.
Beispiel:
import numpy as np
A = np.array([[5, 1], [0, 2]])
b = np.array([1, 2])
x = np.linalg.solve(A, b)
print(x)
Ausgabe:
[0. 1.]
Siehe dazu auch das Kapitel [[Ing Mathematik: Numerisches Lösen von linearen Gleichungssystemen]]. Dort wird dieses Themengebiet u.a. mit weitergehenden Python-Skripten vertieft.
== Aufgabe ==
* Lösen Sie folgendes Gleichungssystem mittels Python (und zur Kontrolle auch händisch):
5x + 6y - 2z = 12
3x - y - 3z = 6
2x + 2y + 4z = 5
= Polynome =
== Ein erstes einfaches Beispiel ==
Gegeben sei das Polynom <math>7x^3+5x^2+1</math>. In Python:
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p)
Ausgabe:
3 2
7 x + 5 x + 1
== Einzelne Polynomwerte berechnen ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
print(p(1.5))
Ausgabe:
35.875
== Polynome integrieren und differenzieren ==
import numpy as np
p = np.poly1d([7, 5, 0, 1])
# 1. Ableitung
p1 = p.deriv()
p2 = p.deriv(1)
# 2. Ableitung
p3 = p.deriv(2)
# Integral
p4 = p.integ()
print(p1)
print(p2)
print(p3)
print(p4)
Ausgabe:
2
21 x + 10 x
2
21 x + 10 x
42 x + 10
4 3
1.75 x + 1.667 x + 1 x
== Nullstellen bestimmen ==
import numpy as np
p = np.poly1d([2, 5, 0, 4])
r = np.roots(p)
print(r)
Ausgabe:
[-2.7621427 +0.j 0.13107135+0.84077099j 0.13107135-0.84077099j]
== Aufgaben ==
* Berechnen Sie den Wert für x = 3 des Polynoms <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Differenzieren und integrieren Sie das Polynom <math>y = 2x^4 - 3x^3 - x + 7</math>.
* Berechnen Sie die Nullstellen von <math>y = 7x^5 - 3x^2 + 12</math>.
= Nichtlineare Gleichungen und Gleichungssysteme =
== Nullstellenbestimmung ==
Löse eine beliebige Gleichung f(x) = 0, z.B. <math> f(x) = x^2 - 5\cos(x) - 10 = 0 </math>:
import scipy
import numpy as np
def f(x):
return x**2 - 5*np.cos(x) - 10
xstart = [-1, 1] # Startwerte
xn = scipy.optimize.root(f, xstart)
print(xn.x)
Ausgabe:
[-2.46813009 2.46813009]
Funktionsgraph:
[[Datei:octave_nichtlin2.jpg]]
== Gleichungssysteme ==
SymPy ist ein externes Modul, das symbolisches Rechnen ('''Sym'''bolic '''Py'''thon) ermöglicht.
Folgende Aufgabe ist dem Buch "Knorrenschild: Numerische Mathematik, Hanser, 2017, Seite 72" entnommen. Zu lösen ist das nichtlineare Gleichungssystem
<math>f_1 = 2x_1 + 4x_2 = 0 </math>
<math>f_2 = 4x_1 + 8x_2^3 = 0</math>
Mit Python ist das so möglich:
import sympy
x1, x2 = sympy.symbols("x1 x2")
f1 = 2*x1 + 4*x2
f2 = 4*x1 + 8*x2**3
s = sympy.solve((f1, f2), x1, x2)
print(s)
Ausgabe:
[(-2, 1), (0, 0), (2, -1)]
Plot:
[[Datei:IngPython_nl_gleichung1.svg|500px]]
= Komplexe Zahlen =
Die imaginäre Einheit wird in Python durch den Buchstaben <code>j</code> symbolisiert. Darstellen kann man eine komplexe Zahl bekannterweise in mehreren Formen:
* Kartesische Darstellung <math>z = \Re(z) + j \cdot \Im(z)</math>
* Polardarstellungen <math>z = r \cdot (\cos(\phi) + j \cdot \sin(\phi)) = r \cdot e^{j\cdot \phi}</math>
Die konjugiert komplexe Zahl ist <math>z^* = \Re(z) - j \cdot \Im(z)</math>
Nachfolgend einige mathematische Operationen mit Python und NumPy.
import numpy as np
z1 = 2 + 5j # kartesische Darstellung
z2 = 3 * np.exp(3j) # Polardarstellung
# Addition
res = z1 + z2
print("z1 + z2 = ", res)
# Multiplikation
res = z1 * z2
print("z1 * z2 = ", res)
# Realteil
res = np.real(z2)
print("Realteil von z2 = ", res)
# Imaginärteil
res = np.imag(z2)
print("Imaginaerteil von z2 = ", res)
# Betrag
res = np.abs(z1)
print("Betrag von z1 = ", res)
# Argument
res = np.angle(z1)
print("Argument von z1 = ", res)
# Konjugiert komplexe Zahl
res = np.conj(z1)
print("Konjugiert komplexe Zahl von z1 = ", res)
Ausgabe:
z1 + z2 = (-0.9699774898013365+5.423360024179601j)
z1 * z2 = (-8.05675510050068-14.003167400647481j)
Realteil von z2 = -2.9699774898013365
Imaginaerteil von z2 = 0.4233600241796016
Betrag von z1 = 5.385164807134504
Argument von z1 = 1.1902899496825317
Konjugiert komplexe Zahl von z1 = (2-5j)
= Interpolation =
import numpy as np
import scipy
import matplotlib.pyplot as plt
# Stützpunkte
xp = np.arange(1, 6)
yp = (0, -5, 2, 7, 6)
ti = np.arange(1, 5, 0.01)
i1 = scipy.interpolate.interp1d(xp, yp, kind = "linear")
i2 = scipy.interpolate.interp1d(xp, yp, kind = "cubic")
plt.plot(xp, yp, "rx")
plt.plot(xp, i1(xp))
plt.plot(ti, i2(ti))
plt.show()
Ausgabe:
[[Datei:PythonIng_interpol1.png]]
= Differenzialrechnung =
== Numerisches Differenzieren ==
Als Beispiel differenzieren wir <math>y = 5x\sin{x}</math> und stellen das Ganze grafisch dar.
from findiff import Diff
import numpy as np
import matplotlib.pyplot as plt
x = np.linspace(0, 10, 1000)
f = 5 * x * np.sin(x)
dx = x[1] - x[0]
# Ableitung
d_dx = Diff(0, dx)
df_dx = d_dx(f)
# Grafik
plt.plot(x, f, label = "y")
plt.plot(x, df_dx, label = "y'")
plt.grid()
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:octave_diff1.jpg]]
<small>findiff ist ein externes Modul. Dieses muss installiert werden (z.B. so: ...\Python\Scripts\pip.exe install --upgrade findiff). Für die Vorgehensweise unter openSUSE Tumbleweed siehe das Kapitel [[Ing_Mathematik:_Python#Mit_VPython | VPython]], nur dass das Ganze mit einer aktuelleren Python-Version exekutiert wird, z.B. mit Python 3.13. Das im Buch "Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler, Rheinwerk" verwendete Modul "scipy.misc" ist veraltet (deprecated ... missbilligt). Lt. [https://docs.scipy.org/doc/scipy-1.17.0/dev/roadmap-detailed.html#misc SciPy-Dokumentation für die Version 1.17.0] wurden alle entsprechenden Features schon entfernt.</small>
== Symbolisches Differenzieren ==
Differenzieren Sie die Funktionen <math>f_1(x) = x^2</math> und <math>f_2(x) = \sin(x)\cos\left(\frac{x}{2}\right)</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2;
f2 = sympy.sin(x) * sympy.cos(x/2.)
d1 = sympy.diff(f1, x)
d2 = sympy.diff(f2, x)
print(d1)
print(d2)
Ausgabe:
2*x
-0.5*sin(0.5*x)*sin(x) + cos(0.5*x)*cos(x)
== Aufgaben ==
* Differenzieren Sie die Funktion <math>y = \log(x) + 10x</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
* Differenzieren Sie die Funktion <math>y = \frac{\sinh(x)}{(1+x)}</math> und stellen Sie y, sowie y' grafisch am Bildschirm dar.
= Integralrechnung =
== Numerisches Integrieren ==
Berechnen Sie das Integral <math>\int_{0}^{3}x^2 dx</math>.
import scipy
def f(x):
return x**2
i = scipy.integrate.quad(f, 0, 3)
print(i)
Ausgabe:
(9.000000000000002, 9.992007221626411e-14)
Das trifft den exakten Wert 9.0 ziemlich genau.
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} dx</math>.
import scipy
import numpy as np
def f(x):
return 2**(-x)
i = scipy.integrate.quad(f, 0, np.inf)
print(i)
Ausgabe:
(1.4426950408889556, 4.486558477977586e-09)
== Symbolisches Integrieren ==
Berechnen Sie <math>\int x^2 \text{d}x</math> und <math>\int \sin{x}\cos{\frac{x}{2}} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f1 = x**2
f2 = sympy.sin(x) * sympy.cos(x/2.)
i1 = sympy.integrate(f1, x)
i2 = sympy.integrate(f2, x)
print(i1)
print(i2)
Ausgabe:
x**3/3
-0.666666666666667*sin(0.5*x)*sin(x) - 1.33333333333333*cos(0.5*x)*cos(x)
Berechnen Sie das Integral <math>\int_{0}^{\infty} 2^{-x} \text{d}x</math>.
import sympy
x = sympy.symbols("x")
f = 2**(-x)
i = sympy.integrate(f, (x, 0, sympy.oo))
print(i)
Ausgabe:
1/log(2)
<code>sympy.oo</code> steht für das {{W|Unendlichzeichen}} <math>\infty</math> (die liegende Acht oder das Möbiusband). Mit <code>sympy.pprint(i)</code> ließe sich letzere Ausgabe etwas schöner schreiben:
1
──────
log(2)
Man beachtete, <code>log</code> steht hier für den natürlichen Logarithmus <code>ln</code>.
== Aufgaben ==
* Integrieren Sie die Funktion <math>y = \log(x) + 10x</math> von 1 bis 5.
* Integrieren Sie die Funktion <math>y = x^3</math> von 0 bis 4.
* Integrieren Sie <math>\int x^x(\log (x) + 1)\mathrm dx</math> symbolisch.
= Gewöhnliche Differenzialgleichungen =
== DGL numerisch lösen ==
Für die Lösung von Differenzialgleichungen steht u.a. die Funktion scipy.integrate.solve_ivp() zur Verfügung. Diese Funktion implementiert auch das Runge-Kutta-Verfahren (RK45).
{{Wikipedia | Runge-Kutta-Verfahren}}
Beispiel <math>y' = x^2 + y^3</math>:
import scipy
import numpy as np
import matplotlib.pyplot as plt
def dy_dx(x, y):
return x**2 + y**3
y0 = [1]
xi = [0, 1]
x = np.arange(0, 1, 0.01)
z = scipy.integrate.solve_ivp(dy_dx, xi, y0, method="RK45", dense_output=True)
y = z.sol(x)
plt.plot(x, y.T)
plt.grid()
plt.show()
[[Datei:PythonIng_dgl1.png]]
== DGL symbolisch lösen ==
Beispiel <math>y' = x^2 + y^3</math>:
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
print(lsg)
Ausgabe:
[Eq(f(x), (-x**2)**(1/3)), Eq(f(x), (-x**2)**(1/3)*(-1 - sqrt(3)*I)/2), Eq(f(x), (-x**2)**(1/3)*(-1 + sqrt(3)*I)/2)]
Mit <code>sympy.pprint</code> (pretty print) lässt sich die Ausgabe etwas übersichtlicher darstellen.
import sympy
x = sympy.symbols("x")
y = sympy.Function("f")(x)
dgl = x**2 + y**3
lsg = sympy.dsolve(dgl, y)
sympy.pprint(lsg)
Ausgabe:
⎡ _____ _____ ⎤
⎢ _____ 3 ╱ 2 3 ╱ 2 ⎥
⎢ 3 ╱ 2 ╲╱ -x ⋅(-1 - √3⋅ⅈ) ╲╱ -x ⋅(-1 + √3⋅ⅈ)⎥
⎢f(x) = ╲╱ -x , f(x) = ────────────────────, f(x) = ────────────────────⎥
⎣ 2 2 ⎦
== Aufgaben ==
* Lösen Sie die Differenzialgleichung <math>y' = \frac{1}{x\cdot y}</math> mit Python. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>m' = -k\cdot m</math>. Kontrollieren Sie das Ergebnis, indem Sie die DGl händisch lösen.
* Lösen Sie die Differenzialgleichung <math>y' = \sqrt{|y|}</math>.
=Laplace-Transformation=
Laplace-Transformation:
<math>F(s) =\mathcal{L} \left\{f\right\}(s) = \int_{0}^{\infty} f(t) \mathrm e^{-st} \,\mathrm{d}t, \qquad s\in\mathbb{C}
</math>
Inverse Laplace-Transformation:
<math>\mathcal{L}^{-1} \left\{F\right\}(t)
= \frac{1}{2 \pi \mathrm j} \int_{ \gamma - \mathrm j \infty}^{ \gamma + \mathrm j \infty} \mathrm e^{st} F(s)\,\mathrm ds
= \begin{cases}
f(t) & \text{für } t \geq 0 \\
0 & \text{für } t < 0
\end{cases}
</math>
Siehe auch [[Ing_Mathematik:_Laplace-Transformation]]
Code:
import sympy
from sympy.abc import t, s
# Laplace-Transformation der Funktion f(t) = 1 (Heaviside-Fkt.)
f = 1
# alternativ: f = sympy.Heaviside(t)
F = sympy.laplace_transform(f, t, s, noconds=True)
print("Laplace-Transformierte F(s):", F)
# Inverse Laplace-Transformation zurück in den Zeitbereich
f_inv = sympy.inverse_laplace_transform(F, s, t)
print("Inverse Transformation f(t):", f_inv)
Ausgabe:
Laplace-Transformierte F(s): 1/s
Inverse Transformation f(t): Heaviside(t)
Die Zeile
from sympy.abc import t, s
steht alternativ für
t = sympy.symbols("t")
s = sympy.symbols("s")
=Fourier-Reihen=
<math>
f(x)\approx \frac{a_{0}}{2}+\sum_{k=1}^{\infty}\left(a_{k}\cos\left(kx\right)+b_{k}\sin\left(kx\right)\right)
</math>
<math>
a_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\cos\left(kx\right)\mathrm dx\quad\text{für }k\geq0
</math>
<math>
b_{k} = \frac{1}{\pi}\int_{-\pi}^{\pi}f(x)\cdot\sin\left(kx\right)\mathrm dx\quad\text{für }k\geq1
</math>
Für die Sägezahnfunktion <math>y=x;\, 0 < x < 2\pi</math> sei die Fourierreihe mit einem Python-Programm (unter Mithilfe von sympy) hergeleitet.
Code:
from sympy import fourier_series, pi, symbols, pprint
x = symbols('x')
f = x
s = fourier_series(f, (x, 0, 2*pi))
pprint(s.truncate(n=4))
Ausgabe:
2⋅sin(3⋅x)
-2⋅sin(x) - sin(2⋅x) - ────────── + π
3
Siehe auch [[Ing Mathematik: Fourierreihen]].
Ein komplizierteres Beispiel:
[[Datei:IngMath fourier bsp13.svg | 300px]]
<math>0\le t < T/2\text{:}\quad f(t) = H</math>
<math>T/2 \le t \le T\text{:}\quad f(t) = \frac{2H}{T}\left( t-\frac{T}{2}\right)</math>
Code:
import sympy as sp
H = sp.Symbol('H', positive=True)
T = sp.Symbol('T', positive=True)
t = sp.Symbol('t')
f = sp.Piecewise(
(H, (t > 0) & (t < T/2)),
(2*H/T*(t-T/2), (t > T/2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Ausgabe:
⎛2⋅π⋅t⎞ ⎛4⋅π⋅t⎞ ⎛6⋅π⋅t⎞ ⎛2⋅π⋅t⎞ ⎛6⋅π⋅t⎞
H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ H⋅sin⎜─────⎟ 2⋅H⋅cos⎜─────⎟ 2⋅H⋅cos⎜─────⎟
⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ ⎝ T ⎠ 3⋅H
──────────── - ──────────── + ──────────── + ────────────── + ────────────── + ───
π 2⋅π 3⋅π 2 2 4
π 9⋅π
=Rechnen mit wirklich großen Zahlen=
Bekannt ist, dass Python kaum Einschränkungen beim Wertebereich von Ganzzahlen hat, z.B.
print(10**300)
Ausgabe (gekürzt):
100000000000000000000...00000000000000000000000000000000000000000000000000000000000000000000000
Ähnliches geht auch mit Gleitpunktzahlen, z.B. durch die Verwendung des Moduls mpmath:
import mpmath
print(mpmath.mpf(1500.4)**mpmath.mpf(300))
Ausgabe:
7.27975299218612e+952
Anderes Beispiel:
from mpmath import mp, pi
mp.dps = 100
print(pi)
Ausgabe:
3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068
mpmath kann noch einiges mehr, dazu sei aber auf die entsprechende Dokumentation auf der mpmath-Homepage verwiesen. mpmath ist Bestandteil von SymPy, kann aber auch separat installiert werden.
Aber auch Python selbst besitzt eine Möglichkeit, um mit großen bzw. exakten Gleitpunktzahlen zu rechnen, nämlich das interne Modul decimal. Dieses hat einige Vorteile gegenüber mpmath, aber auch gravierende Nachteile. Diese seien hier nicht detailliert aufgezählt. Grob gesagt hat decimal im Finanzwesen seine Berechtigung. Für wissenschaftliche Anwendungen wird aber mpmath vorzuziehen sein, da es u.a. vielfältige mathematische Funktionen bereit stellt. Nachfolgend ein einfaches Beispiel mit decimal:
import decimal
print("Potenzierung:", decimal.Decimal(1500.4) ** decimal.Decimal(300.0))
print("Einfache Addition:", 0.1 + 0.2)
decimal.getcontext().prec = 50
print("Addition mit decimal:", decimal.Decimal("0.1") + decimal.Decimal("0.2"))
Ausgabe:
Potenzierung: 7.279752992186121551039839134E+952
Einfache Addition: 0.30000000000000004
Addition mit decimal: 0.3
<u>Aufgabe:</u> Recherchieren Sie im Internet die genauen Vor- und Nachteile von decimal und mpmath. Verwenden Sie dazu auch KI (z.B. von Google, chatgpt).
=Regelungstechnische Aufgabenstellungen=
Für regelungstechnische Aufgaben gibt es u.a. das externe Paket <code>control</code>. Hier soll nicht detailliert darauf eingegangen werden. Anhand eines Beispiels soll anschließend nur die Visualisierung in Form eines Bode-Diagramms und der Sprungantwort gezeigt werden. Gegeben sei ein P-Regler mit <math>R = \frac{5}{2}</math> und eine Strecke <math>S= \frac{1}{30s^3+20s^2+10s+1,5}</math>. Gesucht sei vorerst ein Bode-Diagramm für den offenen Regelkreis und das Führungsverhalten.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke # oder: G0 = ct.series(regler, strecke)
Gw = ct.feedback(G0)
ct.bode_plot(G0, label='G0')
ct.bode_plot(Gw, label='Gw')
plt.show()
[[Datei:PythonIng_bode1.svg]]
Nun noch für obiges Beispiel die Sprungantwort. Diese zeigt einige große Überschwinger, d.h. der Regler kann sicher noch optimiert werden.
import numpy as np
import control as ct
import matplotlib.pyplot as plt
zaehler1 = np.array([1.])
nenner1 = np.array([30., 20., 10., 1.5])
strecke = ct.tf(zaehler1, nenner1)
zaehler2 = np.array([5.])
nenner2 = np.array([2.])
regler = ct.tf(zaehler2, nenner2)
G0 = regler*strecke
Gw = ct.feedback(G0)
t, y = ct.step_response(Gw)
plt.plot(t,y)
plt.title('Sprungantwort')
plt.xlabel('t')
plt.ylabel('h(t)')
plt.grid()
plt.show()
[[Datei:PythonIng_bode3.svg]]
Einige weitere wichtige Daten (Phasenreserve, Amplitudenreserve, Durchtrittsfrequenz) lassen sich mittels der <code>control</code>-Funktion <code>margin()</code> ermitteln. Die Ortskurve lässt sich mit der Funktion <code>nyquist_plot()</code> zeichnen. Dies sei hier aber nicht weiter ausgeführt.
==Aufgaben==
* Zeichen Sie mit Python die Ortskurve für obiges Beispiel.
* Was passiert, wenn man die Reglerverstärkung weiter aufdreht (z.B. auf <math>R = \frac{25}{2}</math>)?
* Wie sehen das Bode-Diagramm und die Sprungantwort aus, wenn ein PI-Regler verwendet wird?
= Stereostatik etc. =
Das Modul SymPy bietet einige Möglichkeiten einfache Bauwerke zu berechnen, z.B. Balken oder Fachwerke. Nachfolgend wird ein einfaches Fachwerk berechnet und gezeichnet.
Python-Code:
from sympy.physics.continuum_mechanics.truss import Truss
t = Truss()
# Knoten
t.add_node(("A", -3, 0), ("B", 0, 0), ("C", 4, 0), ("D", 7, 0),
("E", 6, 1.5), ("F", 2, 3), ("G", -2, 1.5))
# Stäbe
t.add_member(("AB","A","B"), ("BC","B","C"), ("CD","C","D"))
t.add_member(("AG","A","G"), ("GB","G","B"), ("GF","G","F"))
t.add_member(("BF","B","F"), ("FC","F","C"), ("CE","C","E"))
t.add_member(("FE","F","E"), ("DE","D","E"))
# Auflager; roller ... Loslager, pinned ... Festlager
t.apply_support(("A","roller"), ("D","pinned"))
# Einwirkende Kräfte
t.apply_load(("G", 5, 270), ("E", 3, 90))
# Berechnung
t.solve()
print("Reaction Forces: ", t.reaction_loads)
print("Internal Forces: ", t.internal_forces)
# Fachwerk zeichnen
p = t.draw()
p.show()
Ausgabe auf der Konsole:
Reaction Forces: {'R_A_y': 4.20000000000000, 'R_D_x': 0, 'R_D_y': -2.20000000000000}
Internal Forces: {'AB': 2.80000000000000, 'BC': 0.333333333333333, 'CD': -1.46666666666667,
'AG': -5.04777178564958, 'GB': -2.05555555555556, 'GF': -1.23413387432364,
'BF': 0.411111111111111*sqrt(13), 'FC': -0.3*sqrt(13), 'CE': 1.50000000000000,
'FE': 0.284800124843917, 'DE': 2.64407093534026}
Zeichnung:
[[File:PythonIng_fachwerk1.svg|300px]]
Details zu diesem Thema siehe z.B. [https://docs.sympy.org/latest/modules/physics/continuum_mechanics/index.html Continuum Mechanics] oder [https://docs.sympy.org/latest/tutorials/physics/continuum_mechanics/index.html Continuum Mechanics Tutorials]. Auch andere mechanische Probleme werden von SymPy abgehandelt ([https://docs.sympy.org/latest/tutorials/physics/index.html Physics Tutorials]).
== Aufgabe ==
Gegeben sei ein einseitig eingespannter Kragträger. Belastet wird er durch eine Einzellast am Trägerende. Für die Daten siehe folgende ASCII-Skizze:
| 20 kN
//|---> x |
//| V
//|----------------------
//| 10 m |
Elastizitätsmodul E = 2,1*10⁵ N/mm²
Flächenträgheitsmoment I = 0.001 m⁴
Berechnen Sie die Auflagerreaktionen, den Querkraft- und Biegemomentenverlauf, sowie die Verformungen.
Stellen Sie dies mit Hilfe von SymPy graphisch und auch mittels Formeln dar. Verwenden Sie dazu auch pprint (pretty print) aus dem SymPy-Modul. Zwecks Lösungsansatz siehe die oben aufgeführte Seite "Continuum Mechanics Tutorials". Achten Sie auch auf die Einheiten! Kontrollieren Sie das Ganze mittels händischer Rechnung. In dem genannten Tutorial ist von "Singularity Functions" die Rede. Gemeint ist damit in diesem Kontext die {{W|Föppl-Klammer}}.
Einige Python-Programme, vorrangig zu Maschinenelementen, finden sich auf [https://baymp.de/download_python.html BayMP für Python] (Balken, Zahnräder, Stabknickung usw.).
=Thermodynamik=
== PYroMat ==
Für thermodynamische Aufgabenstellungen gibt es verschiedene externe Module. Eines davon ist PYroMat (siehe auch [http://pyromat.org]). Damit lassen sich thermodynamische Stoffdaten für viele Substanzen berechnen.
Beispiel (einige Stoffdaten für Wasser bei 400°C und 20 bar berechnen):
import pyromat as pm
# Wasserdaten laden:
H2O = pm.get('mp.H2O')
# Stoffdaten berechnen:
T = 673.15 # Temperatur in Kelvin
p = 20 # Druck in bar
v = H2O.v(T, p)
h = H2O.h(T, p)
s = H2O.s(T, p)
print(f"Spezifisches Volumen: {v} m³/kg")
print(f"Spezifische Enthalpie: {h} kJ/kg")
print(f"Spezifische Entropie: {s} kJ/(kg K)")
Ausgabe:
Spezifisches Volumen: [0.1512163] m³/kg
Spezifische Enthalpie: [3248.3789473] kJ/kg
Spezifische Entropie: [7.12924142] kJ/(kg K)
<small>
PYroMat muss vorab installiert werden (z.B. mittels pip, in eine virtuelle Umgebung)
</small>
<code>mp</code> steht für "multi phase". Für ein ideales Gas wäre <code>ig</code> zuständig, z.B. <code>'ig.O2'</code>.
Beispiel (T-s-Diagramm für Wasser zeichnen):
import numpy as np
import matplotlib.pyplot as plt
import pyromat as pm
# Konfigurieren
pm.config["unit_pressure"] = "bar"
pm.config["unit_temperature"] = "K"
fluid = pm.get("mp.H2O")
# Temperaturbereich für das Nassdampfgebiet
T_tripel = 273.16
T_crit = 647.096
T = np.linspace(T_tripel, T_crit - 0.1, 200)
# Sättigungslinien berechnen und zeichnen
for x in np.linspace(0.0, 1.0, 5):
s = fluid.s(T=T, x=x)
if(x<=0.0):
plt.plot(s, T, label="Siedelinie x=%3.1f" % x, linewidth=2.0)
elif(x>=1.0):
plt.plot(s, T, label="Taulinie x=%3.1f" % x, linewidth=2.0)
else:
plt.plot(s, T, label="x=%3.1f" % x, linewidth=1.0)
# Isobaren zeichnen
p_values = [0.1, 1, 10, 50, 100]
T_isobar = np.linspace(T_tripel, 1000, 200)
t = 0.7
for p in p_values:
s_iso = fluid.s(T=T_isobar, p=p)
plt.plot(s_iso, T_isobar, 'k-', alpha=0.8, linewidth=0.8)
t += .05
idx = int(len(s_iso) * t)
plt.text(s_iso[idx], T_isobar[idx], f"{p} bar", fontsize=9, alpha=0.8)
# Diagramm zeichnen
plt.title("T-s-Diagramm für Wasser")
plt.xlabel("Spezifische Entropie s in kJ/kg K", fontsize=10)
plt.ylabel("Temperatur T in K", fontsize=10)
plt.legend(loc="best")
plt.grid(True)
plt.show()
Ausgabe (in etwa so):
[[Datei:T-s-Diagramm fuer Wasser.svg|400px]]
== CoolProp ==
Auch mit CoolProp können Stoffdaten berechnet werden. Siehe auch [https://coolprop.org/coolprop/wrappers/Python/index.html]
Beispiel (Wasser bei 20bar und 400°C):
import CoolProp.CoolProp as CP
fluid = 'Water'
T = 673.15 # Temperatur in Kelvin
P = 20e5 # Druck in Pascal
dichte = CP.PropsSI('D', 'T', T, 'P', P, fluid)
enthalpie = CP.PropsSI('H', 'T', T, 'P', P, fluid)
entropie = CP.PropsSI('S', 'T', T, 'P', P, fluid)
print(f"Spez. Volumen: {1/dichte:.6f} m³/kg")
print(f"Spez. Enthalpie: {enthalpie:.2f} J/kg")
print(f"Spez. Entropie: {entropie:.2f} J/kgK")
Ausgabe:
Spez. Volumen: 0.151215 m³/kg
Spez. Enthalpie: 3248344.02 J/kg
Spez. Entropie: 7129.16 J/kgK
== iapws ==
Um Werte für Wasser(dampf) zu erhalten (IAPWS; '''I'''nternational '''A'''ssociation for the '''P'''roperties of '''W'''ater and '''S'''team) gibt es die Bibliothek iapws. Siehe auch [https://iapws.org/] und [https://pypi.org/project/iapws/]
Beispiel (Wasser für 20bar und 400°C):
from iapws import IAPWS97
dampf = IAPWS97(P=2.0, T=673.15)
print(f"Spezifisches Volumen: {dampf.v:.6f} m³/kg")
print(f"Spezifische Enthalpie: {dampf.h:.2f} kJ/kg")
print(f"Spezifische Entropie: {dampf.s:.4f} kJ/(kgK)")
print(f"Phase: {dampf.phase}")
Ausgabe:
Spezifisches Volumen: 0.151208 m³/kg
Spezifische Enthalpie: 3248.23 kJ/kg
Spezifische Entropie: 7.1290 kJ/(kgK)
Phase: Gas
== TESPy ==
Ein anderes Modul für einen anderen Aufgabenzweck ist TESPy ('''T'''hermal '''E'''ngineering '''S'''ystems in '''Py'''thon). Dieses Modul ist für die Anlagensimulation zuständig. Für nähere Informationen siehe [https://tespy.readthedocs.io/en/main/getting_started/introduction.html]. Als Beipiel sei hier vorerst Code, der von der Google KI generiert wurde, angeführt. Der Code wurde überarbeitet, damit keine Warnungen auftreten. Bitte aber den Code trotzdem mit Vorsicht genießen, auch KI-generierter Code kann Fehler aufweisen. Eine Pumpe wird berechnet:
from tespy.components import Sink, Source, Pump
from tespy.connections import Connection
from tespy.networks import Network
# 1. Netzwerk definieren (Zentrales Steuerungselement)
# Wir wählen Wasser als Fluid und bar/Celsius als Einheiten
nw = Network(fluids=["water"])
nw.units.set_defaults(pressure="bar", pressure_difference="bar",
temperature="°C", enthalpy="kJ / kg")
# 2. Komponenten erstellen
eingang = Source("Wasserquelle")
ausgang = Sink("Wasserspeicher")
pumpe = Pump("Speisewasserpumpe")
# 3. Verbindungen definieren (Komponenten miteinander verknüpfen)
c1 = Connection(eingang, "out1", pumpe, "in1")
c2 = Connection(pumpe, "out1", ausgang, "in1")
# Verbindungen dem Netzwerk hinzufügen
nw.add_conns(c1, c2)
# 4. Randbedingungen und Parameter festlegen
# Zustand am Eingang (Druck, Temperatur, Massenstrom, Fluid-Zusammensetzung)
c1.set_attr(
v=1, # Massenstrom: 1 kg/s
T=20, # Temperatur: 20 °C
p=1, # Druck: 1 bar
fluid={"water": 1}, # 100% Wasser
)
# Zustand am Ausgang / Zielwerte der Pumpe
c2.set_attr(p=10) # Ziel-Druck nach der Pumpe: 10 bar
# Pumpeneigenschaften festlegen
pumpe.set_attr(eta_s=0.8) # Isentroper Wirkungsgrad von 80%
# 5. Simulation ausführen
nw.solve(mode="design")
# 6. Ergebnisse ausgeben
nw.print_results()
# Spezifische Werte direkt auslesen
print("\n--- Auswertung ---")
print(f"Erforderliche Pumpenleistung: {pumpe.P.val / 1000:.2f} kW")
print(f"Temperatur nach der Pumpe: {c2.T.val:.2f} °C")
Ausgabe (gekürzt):
iter | residual | progress | massflow | pressure | enthalpy | fluid | component
-------+------------+------------+------------+------------+------------+------------+------------
1 | 7.04e+04 | 12 % | 9.96e+02 | 0.00e+00 | 8.81e+04 | 0.00e+00 | 0.00e+00
2 | 5.91e-12 | 100 % | 1.11e-13 | 0.00e+00 | 7.39e-12 | 0.00e+00 | 0.00e+00
3 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
4 | 5.80e-12 | 100 % | 0.00e+00 | 0.00e+00 | 7.25e-12 | 0.00e+00 | 0.00e+00
Total iterations: 4, Calculation time: 0.01 s, Iterations per second: 480.85
##### RESULTS (Pump) #####
+-------------------+----------+----------+-----------+----------+----------+----------+
| | P | pr | dp | eta | eta_s | head |
|-------------------+----------+----------+-----------+----------+----------+----------|
| Speisewasserpumpe | 1.12e+06 | 1.00e+01 | -9.00e+00 | 8.00e-01 | 8.00e-01 | 9.19e+01 |
+-------------------+----------+----------+-----------+----------+----------+----------+
...
...
--- Auswertung ---
Erforderliche Pumpenleistung: 1124.77 kW
Temperatur nach der Pumpe: 20.07 °C
= Stochastik =
Die {{W|Stochastik}} ist ein sehr weites Feld. Hier werden etliche wichtige Themen kurz angerissen. Python stellt mit den Moduln math und statistics Software zu diesem Zwecke bereit. math und statistics sind bereits im Lieferumfang von Python enthalten. Aber auch mit den externen Modulen NumPy, SciPy, stochastic und pandas kann man Stochastik in Python betreiben. Die Theorie der Wahrscheinlichkeitsrechnung und Statistik soll etwas später in Band 5 dieser Buchreihe behandelt werden.
== Lageparameter ==
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
m1 = statistics.mean(werte)
m2 = statistics.mode(werte)
m3 = statistics.median(werte)
print("Arithmetischer Mittelwert = ", m1)
print("Modalwert = ", m2)
print("Median = ", m3)
Ausgabe:
Arithmetischer Mittelwert = 3.5
Modalwert = 1
Median = 3.0
== Streuungsparameter ==
Beispiel (Berechnung der Standardabweichung):
import statistics
werte = [1, 3, 4, 4, 1, 7, 9, 1, 2, 3]
s = statistics.stdev(werte)
print("Standardabweichung = ", s)
Ausgabe:
Standardabweichung = 2.6770630673681683
Beispiel (Berechnung des Variationskoeffizienten V = Standardabweichung/Mittelwert)
import numpy as np
from scipy import stats
import statistics
k = 50
dat1 = [14, 21, 18, 25, 30, 17, 20]
dat = np.array(dat1)
# Mit SciPy
v = stats.variation(dat)
vddof = stats.variation(dat, ddof=1)
print("V SciPy: ", v)
print("V DDOF SciPy: ", vddof)
print(k*"-")
# mit NumPy
mittelwert1 = np.mean(dat)
std_abw1 = np.std(dat)
std_abw1ddof = np.std(dat, ddof=1)
v1= std_abw1 / mittelwert1
v1ddof = std_abw1ddof / mittelwert1
print("Mittelwert NumPy: ", mittelwert1)
print("Std.abw. NumPy: ", std_abw1)
print("Std.abw. DDOF NumPy: ", std_abw1ddof)
print("V NumPy: ", v1)
print("V DDOF NumPy: ", v1ddof)
print(k*"-")
# nur mit reinem Python
mittelwert2 = statistics.mean(dat1)
std_abw2 = statistics.stdev(dat1)
v2 = std_abw2 / mittelwert2
print("Mittelwert Python: ", mittelwert2)
print("Std.abw. Python: ", std_abw2)
print("V Python:", v2)
print(k*"-")
Ausgabe:
V SciPy: 0.23890355966467272
V DDOF SciPy: 0.25804533701889254
--------------------------------------------------
Mittelwert NumPy: 20.714285714285715
Std.abw. NumPy: 4.948716593053935
Std.abw. DDOF NumPy: 5.3452248382484875
V NumPy: 0.23890355966467272
V DDOF NumPy: 0.2580453370188925
--------------------------------------------------
Mittelwert Python: 20.714285714285715
Std.abw. Python: 5.3452248382484875
V Python: 0.2580453370188925
--------------------------------------------------
Der Unterschied bei der Standardabweichung zwischen reinem Python und den externen Bibliotheken SciPy und NumPy entsteht dadurch, dass einmal durch (n-1) und das andere Mal nur durch n dividiert wird. Dies kann bei NumPy und SciPy dadurch entschärft werden, indem <code>ddof=1</code> gesetzt wird. ddof steht für '''D'''elta '''D'''egrees '''o'''f '''F'''reedom. <small>Je größer die Anzahl der Datensätze n wird, umso weniger spielt das eine Rolle.</small>
== Kombinatorik ==
Beispiel:
import math
n = 7
k = 5
print("n! = ", math.factorial(n))
print("Kombinationen (n über k) = ", math.comb(n, k))
Ausgabe:
n! = 5040
Kombinationen (n über k) = 21
Siehe zu diesem Thema auch [[Ing Mathematik: Permutationen, Kombinationen, binomischer Lehrsatz]]. Die Anzahlen lassen sich einfach aus den dortigen Formeln ermitteln, z.B. bei Permutationen mit <math>n!</math> oder Variationen mit Wiederholungen als <math>n^k</math>. Will man die Kombinationen oder Variationen aber auch als Liste ausgeben, so kann das Modul <code>itertools</code> nützlich sein.
Beispiel (Variationen ohne Wiederholung):
from itertools import permutations
menge = ["A", "B", "C", "D"] # n = 4
k = 3
variationen = list(permutations(menge, k))
for v in variationen:
print("".join(v))
print(50*"-")
print(len(variationen))
Ausgabe (gekürzt):
ABC
ABD
ACB
...
DCA
DCB
--------------------------------------------------
24
Siehe zum Modul <code>itertools</code> auch die Website [https://docs.python.org/3/library/itertools.html].
* Variationen mit Wiederholung: <code>itertools.product()</code>
* Kombinationen ohne Wiederholung: <code>itertools.combinations()</code>
* Kombinationen mit Wiederholung: <code>itertools.combinations_with_replacement()</code>
== Zufallszahlen ==
Beispiel:
import random
# Ganzzahlige Zufallszahl von 1 bis 10
zufallszahl1 = random.randint(1, 10)
# Gleitpunktzahlen
# zwischen 0.0 und 1.0
zufallszahl2 = random.random()
# Zahl zwischen 1.5 und 9.5
zufallszahl3 = random.uniform(1.5, 9.5)
# aus Liste auswählen
farbe = ["Rot", "Grün", "Blau"]
zufallswert = random.choice(farbe)
print(zufallszahl1)
print(zufallszahl2)
print(zufallszahl3)
print(zufallswert)
Ausgabe, z.B.:
5
0.14147945849015753
6.894003397570905
Rot
Benötigt man mehrere Zufallszahlen, so ist das Modul <code>numpy</code> zu bevorzugen, z.B.:
* Normalverteilung: <code>np.random.normal(...)</code>
* Gleichverteilung: <code>np.random.uniform(...)</code>
== Histogramm ==
Zum Thema Histogramm siehe {{W|Histogramm}}.
Beispiel (mit Matplotlib):
import matplotlib.pyplot as plt
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
plt.hist(daten, bins=25, edgecolor='darkgray')
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm.svg|300px]]
Beispiel (mit Seaborn):
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
daten = np.random.normal(loc=50, scale=10, size=1000)
sns.set_theme(style="darkgrid")
sns.histplot(data=daten)
plt.show()
Ausgabe:
[[Datei:IngMath_histogramm2.svg|300px]]
Das Kürzel <code>sns</code> ist Konvention und steht für die fiktive Figur '''S'''amuel '''N'''orman '''S'''eaborn aus der US-Fernsehserie {{W|The West Wing – Im Zentrum der Macht | The West Wing}}.
== Box-Plot ==
[[File:Elements of a boxplot.svg|400px]]
Siehe auch {{W|Box-Plot}}.
Beispiel (mit Seaborn erstellt):
import seaborn as sns
import matplotlib.pyplot as plt
df = sns.load_dataset("tips")
sns.boxplot(data=df, x="day", y="tip", hue="day", legend=False)
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot.svg|400px]]
Beispiel (mit Matplotlib erstellt):
import matplotlib.pyplot as plt
daten = [12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25]
plt.boxplot(daten, patch_artist=True)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
Ausgabe:
[[Datei:IngMath_boxplot2.svg|300px]]
Um mehrere Box-Plots unterschiedlicher Farbe mit Matplotlib in einem Diagramm zu zeichnen, können Sie folgendermaßen vorgehen:
import matplotlib.pyplot as plt
daten = [[12, 15, 18, 19, 22, 25, 28, 30, 31, 35, 42, 55, 12, 25],
[10, 19, 20, 21, 20, 30, 19, 40, 11, 17, 19, 21]]
farben = ["green", "blue"]
boxplot = plt.boxplot(daten, patch_artist=True)
for patch, farbe in zip(boxplot['boxes'], farben):
patch.set_facecolor(farbe)
plt.title("Boxplot mit Matplotlib")
plt.ylabel("Daten")
plt.show()
== Regressionsrechnung ==
Beispiel:
import numpy as np
import matplotlib.pyplot as plt
# Messpunkte
x = np.array([1, 3, 5, 6, 8, 10, 20])
y = np.array([3, 4, 5, 5, 7, 9, 11])
# Regressionskurve (Grad 1 = lineare Regression, 2 = Polynom-Regression 2. Gr.)
# y = kx + d
k, d = np.polyfit(x, y, deg=1)
# y = ax**2 + bx + c
a, b, c = np.polyfit(x, y, deg=2)
x_l = np.linspace(1, 20, 100)
y_p = a * x_l**2 + b * x_l + c
# Zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.plot(x, k*x + d, color='blue', label='Regressionsgerade')
plt.plot(x_l, y_p, color='red', label='Regressionspolynom 2. Gr.')
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
[[Datei:IngMath_regression.svg|400px]]
== Korrelationsrechnung ==
Beispiel:
import pandas as pd
import matplotlib.pyplot as plt
# Messdaten
x = [1, 3, 4, 5, 6]
y = [2, 4, 6, 8, 5]
daten = {'X': x, 'Y': y}
df = pd.DataFrame(daten)
# Korrelation
korr = df['X'].corr(df['Y'])
print(f"Korrelationskoeff.: {korr}")
# Messpunkte zeichnen
plt.scatter(x, y, color='green', label='Messpunkte')
plt.grid()
plt.axis("equal")
plt.legend(loc="best")
plt.show()
Ausgabe:
Korrelationskoeff.: 0.7556096518348252
[[Datei:IngMath_korrelation.svg|300px]]
== Mengen und Venn-Diagramme ==
Beispiel:
import matplotlib.pyplot as plt
from matplotlib_venn import venn2
menge_a = {1, 2, 3, 4, 5, 6}
menge_b = {4, 5, 6, 7, 8}
vereinigung = menge_a | menge_b
schnitt = menge_a & menge_b
print("Vereinigungsmenge = ", vereinigung)
print("Schnittmenge = ", schnitt)
venn2([menge_a, menge_b], set_labels=('Menge A', 'Menge B'))
plt.show()
Ausgabe:
Vereinigungsmenge = {1, 2, 3, 4, 5, 6, 7, 8}
Schnittmenge = {4, 5, 6}
[[Datei:IngMath_venn.svg|300px]]
Siehe auch {{W|Mengendiagramm#Venn-Diagramme}}.
== Verteilungs- und Dichtefunktion ==
* CDF ... '''C'''umulative '''D'''istribution '''F'''unction, Verteilungsfunktion
* PDF ... '''P'''robability '''D'''ensity '''F'''unction, Dichtefunktion
Beispiel (Normalverteilung):
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
my, sigma = 0, 1
x = np.linspace(-4, 4, 50)
pdf = norm.pdf(x, my, sigma)
cdf = norm.cdf(x, my, sigma)
plt.plot(x, pdf, lw=2, label="Dichtefunktion")
plt.plot(x, cdf, lw=2, label="Verteilungsfunktion")
plt.legend()
plt.grid()
plt.show()
Ausgabe:
[[Datei:IngMath_cdf_pdf.svg|300px]]
Beispiel (<math>\chi^2</math>-Verteilung):
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats as stats
x = np.linspace(0, 20, 500)
# df ... degree of freedom, Freiheitsgrad
pdf = (stats.chi2.pdf(x, df=2), stats.chi2.pdf(x, df=5), stats.chi2.pdf(x, df=10))
for i in range(0,3):
if(i==0):
lab = "Freiheitsgrad 2"
elif(i==1):
lab = "Freiheitsgrad 5"
else:
lab = "Freiheitsgrad 10"
plt.plot(x, pdf[i], label=lab, lw=2)
plt.grid()
plt.legend()
plt.show()
Ausgabe:
[[Datei:IngMath_chi2.svg | 300px]]
== Schätzen und Testen ==
=== Intervallschätzung ===
Als Beispiel seien Daten gegeben, die von ''Dürr, Mayer: Wahrscheinlichkeitsrechnung und Schließende Statistik; 7. Aufl., Hanser, 2014, Seite 137'' stammen. Und zwar soll das 95%-Vertrauensintervall für den Mittelwert des Kaloriengehalts (kcal/100g) von Hähnchen ermittelt werden. Wir wollen das mit Python inkl. NumPy und SciPy durchführen. Die Stichprobe ist groß (50 Hähnchen):
Python-Code:
import numpy as np
import scipy.stats as stats
# Stichprobe
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203]
# Parameter definieren
konfidenzniveau = 0.95
mean = np.mean(daten)
std = np.std(daten, ddof=1)
stdfehler = stats.sem(daten)
intervall = stats.norm.interval(confidence=konfidenzniveau, loc=mean, scale=stdfehler)
print(f"Mittelwert: {mean}")
print(f"Standardabweichung: {std}")
print(f"Konfidenzintervall: {intervall}")
Ausgabe:
Mittelwert: 215.48
Standardabweichung: 33.14238915925757
Konfidenzintervall: (np.float64(206.29356722321992), np.float64(224.66643277678006))
Diese Werte stimmen gerundet mit denen im genannten Buch überein. Zum Code selbst:
* sem steht für '''s'''tandard '''e'''rror of the '''m'''ean.
* <code>scipy.stats.norm</code> ... Modul für die Normalverteilung.
=== Punktschätzung ===
Gleiche Daten wie oben bei der Intervallschätzung.
Python-Code:
import numpy as np
from scipy import stats
daten = [309, 202, 234, 252, 240, 225, 241, 212, 118, 191,
236, 204, 213, 220, 219, 218, 195, 159, 195, 206,
207, 232, 215, 210, 204, 332, 241, 225, 235, 193,
238, 187, 189, 203, 190, 252, 227, 212, 180, 178,
242, 236, 174, 240, 195, 223, 213, 209, 200, 203
]
mu_hat, sigma_hat = stats.norm.fit(daten)
print(f"Schätzer für den Erwartungswert (μ): {mu_hat:.4f}")
print(f"Schätzer für die Standardabweichung (σ): {sigma_hat:.4f}")
Ausgabe:
Schätzer für den Erwartungswert (μ): 215.4800
Schätzer für die Standardabweichung (σ): 32.8093
=== Hypothesentests ===
Beispiel:
import numpy as np
import scipy.stats as stats
x_quer = 12.075 # Stichproben-Mittelwert
var = 0.069 # Stichproben-Varianz
n = 90 # Stichprobengröße
my_0 = 12.0 # Nullhypothese
alpha = 0.05 # Signifikanzniveau
z_stat = (x_quer - my_0) / np.sqrt(var / n)
p_val = 2 * (1 - stats.norm.cdf(np.abs(z_stat)))
print(f"Z-Statistik: {z_stat:.4f}")
if p_val < alpha:
print(f"p-Wert: {p_val:.6f} < alpha:", alpha)
print("Die Nullhypothese wird verworfen.")
else:
print(f"p-Wert: {p_val:.6f} > alpha:", alpha)
print("Die Nullhypothese wird nicht verworfen.")
Ausgabe:
Z-Statistik: 2.7087
p-Wert: 0.006755 < alpha: 0.05
Die Nullhypothese wird verworfen.
== Statistische Qualitätskontrolle ==
Beispiel (Mittelwertkarte):
import numpy as np
import matplotlib.pyplot as plt
# Gegeben
sollwert = 50.0
varianz = 4.0
stichproben_umfang = 1
daten = [49.5, 50.2, 53.0, 48.1, 52.6, 53.4, 49.8]
# Berechnung
standardabweichung = np.sqrt(varianz)
streuung = standardabweichung / np.sqrt(stichproben_umfang)
cl = sollwert
ucl = cl + 3 * streuung
lcl = cl - 3 * streuung
# Darstellung
plt.plot(daten, marker='o', linestyle='-', color='b', label='Messdaten')
plt.axhline(cl, color='green', linestyle='-', label=f'CL: {cl}')
plt.axhline(ucl, color='red', linestyle='--', label=f'UCL: {ucl:.2f}')
plt.axhline(lcl, color='red', linestyle='--', label=f'LCL: {lcl:.2f}')
plt.title('Mittelwertkarte')
plt.xlabel('Stichprobe')
plt.ylabel('Wert')
plt.legend(loc='lower left')
plt.grid(True)
plt.show()
Ausgabe:
[[Datei:IngMath_mittelwertkarte.svg|300px]]
Siehe auch {{W|Shewhart-Regelkarte}} und {{W|Qualitätsregelkarte}}.
* UCL ... '''U'''pper '''C'''ontrol '''Limit''', Obere Eingriffsgrenze
* LCL ... '''L'''ower '''C'''ontrol '''Limit''', Untere Eingriffsgrenze
* CL ... '''C'''enter '''L'''ine, Mittellinie
= Ein- und Ausgabe =
== print ==
Die Anweisung print haben wir schon oft verwendet. Hier soll anhand von Beispielen kurz beschrieben werden, was der Befehl print leisten kann.
print("Hallo", "Welt", 1, sep="-")
print("Hallo", end=" ")
print("Welt")
Ausgabe:
Hallo-Welt-1
Hallo Welt
== input ==
a = int(input("Zahl 1: "))
b = int(input("Zahl 2: "))
print("a + b = ", a+b)
Ausgabe (nach Eingabe der beiden Ganzzahlen):
Zahl 1: 4
Zahl 2: 5
a + b = 9
== Aus Dateien lesen ==
Es seinen die datei.txt
Hallo Welt.
Wie geht es dir?
...
und test1.py
dat = open("datei.txt", mode = "r")
print(dat.read())
dat.close()
Ausgabe
Hallo Welt.
Wie geht es dir?
...
Mit dem open()-Befehl wird die Datei datei.txt im Lesemodus geöffnet (r ... read). Mit dem read()-Befehl wird die Datei eingelesen und mittels print ausgegeben.
== In Dateien schreiben ==
dat = open("datei.txt", mode = "a", encoding = "utf-8")
dat.write("Hänge Zeile an\n")
dat.close()
Die Datei datei.txt sieht nach Abarbeitung des obigen Skripts nun so aus
Hallo Welt.
Wie geht es dir?
...
Hänge Zeile an
Es wird die Datei im Schreibmodus geöffnet (a ... append (anhängend), w ... write (überschreibend)).
write() fügt hier also eine Zeile Text am Dateiende ein. close() schließt die Datei wieder.
Das close() kann man sich mit der with-Anweisung auch sparen.
with open("datei.txt", mode="a", encoding="utf-8") as dat:
dat.write("Hänge Zeile an\n")
= Benutzeroberflächen erstellen =
== tkinter ==
{{Wikipedia | Tkinter}}
Python bietet standardmäßig das Modul tkinter zur Programmierung von Benutzeroberflächen. Es müssen also bei der Verwendung von tkinter keine externen Module installiert werden. Hier wird eine (sehr) kurze Einführung in das Erstellen von grafischen Oberflächen mittels tkinter gegeben.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
win.minsize(300, 50)
but = tk.Button(win, text = "Push the button")
but.pack()
win.mainloop()
Ausgabe:
[[Datei:PythonIng_gui1.jpg]]
Ein etwas komplizierteres Beispiel sei nachfolgend gezeigt. Es sollen zwei Strings miteinander verknüpft und ausgegeben werden.
import tkinter as tk
win = tk.Tk()
win.title("Hallo Welt!")
def on_button_clicked():
str = ent1.get() + ent2.get()
lab2["text"] = str
ent1 = tk.Entry(win)
ent2 = tk.Entry(win)
lab1 = tk.Label(win, text="verknuepfen mit")
lab2 = tk.Label(win, text="")
but = tk.Button(win, text = "=", command=on_button_clicked)
ent1.pack(side="left")
lab1.pack(side="left")
ent2.pack(side="left")
but.pack(side="left")
ent2.pack(side="left")
lab2.pack(side="left")
win.mainloop()
Ausgabe (vor der Eingabe der Teilstrings):
[[Datei:PythonIng_gui2.jpg]]
Ausgabe (nach der Eingabe der Teilstrings und dem Drücken des =-Buttons):
[[Datei:PythonIng_gui3.jpg]]
== curses ==
{{Wikipedia | curses}}
Mit dem curses-Modul lassen sich u.a. TUIs ('''T'''ext '''U'''ser '''I'''nterfaces) erstellen. Ein sehr einfaches Beispiel zur allgemeinen Funktionsweise wird nachstehend geliefert.
import curses
stdscr = curses.initscr()
curses.start_color()
curses.init_pair(1, curses.COLOR_RED, curses.COLOR_WHITE)
stdscr.clear()
stdscr.addstr("Hallo Welt", curses.color_pair(1))
stdscr.refresh()
stdscr.getch()
curses.endwin()
Als Ausgabe sollte <span style="color:#FF0000;">Hallo Welt</span> (rote Schrift auf weißem Hintergrund) auf dem Terminal/der Konsole erscheinen. Getestet wurde dies mit openSUSE Tumbleweed, Python-Version 3.13.12. Das entsprechende Python-curses-Package muss installiert sein.
Allgemeine Informationen zur Terminal-/Konsolengröße und Cursorposition liefert folgendes Programm:
import curses
stdscr = curses.initscr()
stdscr.addstr(3, 5, "LINES: %d" % curses.LINES)
stdscr.addstr(4, 5, "COLS: %d" % curses.COLS)
(y,x) = stdscr.getyx()
stdscr.addstr(5, 5, "Momentane Cursorposition: [%d, %d]" % (y, x))
(y,x) = stdscr.getbegyx()
stdscr.addstr(6, 5, "Koordinatenursprung: [%d, %d]" % (y, x))
(y,x) = stdscr.getmaxyx()
stdscr.addstr(7, 5, "Fenstergröße: [%d, %d]" % (y, x))
stdscr.addstr(11, 2, "Taste drücken -> Ende")
stdscr.refresh()
stdscr.getch()
curses.endwin()
Es sollte sich in etwa folgende Ausgabe ergeben:
LINES: 44
COLS: 110
Momentane Cursorposition: [4, 15]
Koordinatenursprung: [0, 0]
Fenstergröße: [44, 110]
Taste drücken -> Ende
Zur Funktionsweise von curses siehe auch das Wikibook [[ncurses]]. Zum Verständnis sind dort allerdings elementare Kenntnisse in der Programmiersprache C erforderlich.
== Qt ==
{{Wikipedia | Qt (Bibliothek)}}
Auch für das Qt-Framework gibt es eine Anbindung an Python. Nachfolgend ein einfaches Beispiel.
import sys
from PySide6.QtWidgets import QApplication, QLabel
app = QApplication(sys.argv)
label = QLabel("Hallo Welt!")
label.show()
sys.exit(app.exec())
Ausgabe:
[[Datei:PythonIng_gui10.png]]
== Gtk ==
{{Wikipedia | GTK (Programmbibliothek)}}
Eine idente Ausgabe, wie oben für Qt gezeigt, erzeugt z.B. folgendes Gtk-Programm:
import gi
gi.require_version("Gtk", "4.0")
from gi.repository import Gtk
def on_activate(app):
win = Gtk.ApplicationWindow(application=app)
lab = Gtk.Label(label="Hallo Welt!")
win.set_child(lab)
win.present()
app = Gtk.Application()
app.connect('activate', on_activate)
app.run(None)
Auch für die Benutzung von Qt und Gtk müssen die jeweiligen Packages installiert sein. Getestet wurden die entsprechenden Python-Programme nur unter openSUSE Tumbleweed. Wie das GTK-Paket unter MS Windows 11 installiert wird, siehe z.B. [https://www.gtk.org/docs/installations/windows Setting up GTK for Windows].
Damit sei aber das Thema "Benutzeroberflächen erstellen" hier abgeschlossen, da dies schon ein sehr spezielles Aufgabengebiet ist, das eher Informatiker und nicht so sehr Ingenieure anspricht. Bei Bedarf siehe aber ggf. die entsprechenden Links unten in diesem Tutorial. Dort sind weiterführende Informationen zu finden.
= Pandas kurz erklärt =
Hier wird kurz auf das externe Modul Pandas eingegangen. Pandas steht für '''Pan'''el '''Da'''ta und ist ein Modul für die Datenanalyse und -manipulation.
== Series ==
Vorstellbar ist eine "Series" wie eine einzelne Spalte in einem Tabellenkalkulationsprogramm.
Beispiel (Index implizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5]) # Temperaturwerte
print(temp)
Ausgabe:
0 8.5
1 11.0
2 12.5
3 10.0
4 13.0
5 11.0
6 14.5
dtype: float64
Das Kürzel <code>pd</code> ist Konvention. Es seien Temperaturwerte gegeben. Die erste Spalte bei der Ausgabe ist der Index. Die zweite Spalte enthält die Werte.
Beispiel (separater Zugriff auf den Index und auf die Werte):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5])
print(temp.index)
print(temp.values)
Ausgabe:
RangeIndex(start=0, stop=7, step=1)
[ 8.5 11. 12.5 10. 13. 11. 14.5]
Beispiel (Index explizit vorgegeben):
import pandas as pd
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
print("*** Die gesamte Series ***")
print(temp)
print("*** Temperatur am Donnerstag ***")
print(temp["Do"])
print("*** Tage wärmer als 12 Grad ***")
temp_gr_12 = temp[temp > 12]
print(temp_gr_12)
Ausgabe:
*** Die gesamte Series ***
Mo 8.5
Di 11.0
Mi 12.5
Do 10.0
Fr 13.0
Sa 11.0
So 14.5
dtype: float64
*** Temperatur am Donnerstag ***
10.0
*** Tage wärmer als 12 Grad ***
Mi 12.5
Fr 13.0
So 14.5
dtype: float64
== DataFrame ==
Ein DataFrame entspricht einer Tabelle.
Beispiel (Erzeugen eines DataFrames):
import pandas as pd
tag = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
v1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=tag)
v2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=tag)
v3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=tag)
tab = pd.concat([v1, v2, v3], axis=1)
tab.columns = stadt
print(tab)
print(type(tab))
Ausgabe:
Linz Salzburg Innsbruck
Mo 1 8 Hallo
Di 2 9 16
Mi 3 10 17
Do 4 11 18
Fr 5 12 19
Sa 6 13 20
So 7 14 21
<class 'pandas.core.frame.DataFrame'>
Wir haben hier drei Datenspalten (v1, v2, v3) mit den Spaltennamen "Linz", "Salzburg" und "Innsbruck", sowie sieben Zeilen "Mo" bis "So".
Beispiel (Zugriff auf eine Spalte):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab["Salzburg"])
Ausgabe:
Mo 8
Di 9
Mi 10
Do 11
Fr 12
Sa 13
So 14
Name: Salzburg, dtype: int64
Beispiel (Zugriff auf eine Zeile):
import pandas as pd
ind = ["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"]
stadt = ["Linz", "Salzburg", "Innsbruck"]
temp1 = pd.Series([1, 2, 3, 4, 5, 6, 7],
index=ind)
temp2 = pd.Series([8, 9, 10, 11, 12, 13, 14],
index=ind)
temp3 = pd.Series(["Hallo", 16, 17, 18, 19, 20, 21],
index=ind)
tab = pd.concat([temp1, temp2, temp3], axis=1)
tab.columns = stadt
print(tab.loc["Di"])
Ausgabe:
Linz 2
Salzburg 9
Innsbruck 16
Name: Di, dtype: object
== Grafiken erstellen ==
Hier sei nur ein Torten- oder Kreisdiagramm gezeichnet:
import pandas as pd
import matplotlib.pyplot as plt
temp = pd.Series([8.5, 11.0, 12.5, 10.0, 13.0, 11.0, 14.5],
index=["Mo", "Di", "Mi", "Do", "Fr", "Sa", "So"])
expl = [0, 0.2, 0, 0, 0, 0, 0]
temp.plot.pie(figsize=(5,5), explode=expl)
plt.show()
Ausgabe:
[[Datei:IngPython_pandas1.svg|350px]]
Die <code>figsize</code> hat nichts mit der Spaltenanzahl zu tun, sondern setzt die Fenster- oder Diagrammgröße in Inches (Breite * Höhe).
Mit Pandas kann man auch noch andere Diagrammarten erstellen, z.B. Linien- oder Balkendiagramme. Dies wird hier aber nicht vorgeführt.
== Arbeiten mit CSV- und LibreOffice-Dateien ==
Gegeben sei eine CSV-Datei test1.csv:
Mai;Juni;Juli
12;17;45
15;65;65
16;32;23
4;14;7
23;17;Keine Daten verfügbar
67;Keine Daten verfügbar;45
15;24;12
Lesen von dieser CSV-Datei:
import pandas as pd
tab = pd.read_csv("test1.csv", sep=";")
print(tab)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Schreiben in eine CSV-Datei test2.csv:
import pandas as pd
val = pd.read_csv("test1.csv", sep=";")
val.to_csv("test2.csv", index=False)
Ausgabedatei:
Mai,Juni,Juli
12,17,45
15,65,65
16,32,23
4,14,7
23,17,Keine Daten verfügbar
67,Keine Daten verfügbar,45
15,24,12
Die Ausgabedatei ist beinahe gleich wie die Eingabedatei. Es werden aber Kommas statt Strichpunkten verwendet. Daher kommt auch der Name CSV ('''C'''omma '''S'''eparated '''V'''alue). Will man wieder Strichpunkte, so kann man dies über den Parameter <code>sep=";"</code> in der <code>to_csv</code>-Funktion machen.
Um direkt von einer ODS-Datei (LibreOffice Calc, '''O'''pen '''D'''ocument '''S'''preadsheet) zu lesen muss das Modul odfpy extra installiert sein (per YaST, pip etc.). Gelesen wird dann folgendermaßen:
import pandas as pd
df = pd.read_excel('test1.ods', engine='odf')
print(df)
Ausgabe:
Mai Juni Juli
0 12 17 45
1 15 65 65
2 16 32 23
3 4 14 7
4 23 17 Keine Daten verfügbar
5 67 Keine Daten verfügbar 45
6 15 24 12
Die Datei "test1.ods" sei die Datei, aus der das obige "test1.csv" generiert wurde. Schreiben kann man ebenfalls in eine ODS-Datei:
import pandas as pd
daten = {
"Name": ["Hugo", "Richie", "Wilhelmine"],
"Alter": [38, 30, 29],
"Ort": ["Linz", "Innsbruck", "Salzburg"]
}
tab = pd.DataFrame(daten)
with pd.ExcelWriter("test2.ods", engine="odf") as writer:
tab.to_excel(writer, sheet_name="Daten", index=False)
Es ergibt sich eine "test2.ods"-Datei (Screenshot):
[[Datei:IngPython_pandas2.png|250px]]
== Sonstiges ==
Hier seien stichpunktartig einige weitere Features von Pandas angeführt:
* {{W|Pivot-Tabelle|Pivot-Tabellen}} (pivot ... Dreh-, Angelpunkt): Zweck - große Datenmengen schnell zusammenfassen, filtern und analysieren.
* NaN ('''n'''ot '''a''' '''n'''umber): In einem Datensatz fehlt ein Wert oder ist nicht definiert.
* groupby-Funktion: Daten strukturieren, aggregieren oder Zwischensummen bilden.
* {{W|Binning#Datenverarbeitung_und_-analyse|Binning}}: Klassenbildung.
* Mehrstufige Indizierung (Hierarchical Indexing oder MultiIndex)
* Zeitreihen (Time Series)
Für tiefergehende und weiterführende Informationen wird auf das Buch von ''Klein: Numerisches Python; Hanser, 2023'' und [https://pandas.pydata.org/ pandas] verwiesen.
= Style Guide, flake8, pylint, Black etc. =
== Style Guide ==
Wie man schönen und richtigen Python-Code schreibt, erfahren Sie in
* [https://peps.python.org/pep-0008/ PEP 8 – Style Guide for Python Code]
== Formatter und Linter ==
Ein Modul, das prüft, ob die Richtlinien im Style Guide eingehalten wurden, ist ''flake8'':
* [https://flake8.pycqa.org/en/latest/ Flake8: Your Tool For Style Guide Enforcement]
Code formatieren kann man auch mit [https://pypi.org/project/black/ Black]. Z.B. übersetzt <code>black test1.py</code> die Datei <code>test1.py</code>
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)),
(2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
in
import sympy as sp
H = sp.Symbol("H", positive=True)
T = sp.Symbol("T", positive=True)
t = sp.Symbol("t")
f = sp.Piecewise(
(H, (t > 0) & (t < T / 2)), (2 * H / T * (t - T / 2), (t > T / 2) & (t < T))
)
f_series = sp.fourier_series(f, (t, 0, T))
sp.pprint(f_series.truncate(4))
Die Programmausgabe ist
reformatted test1.py
All done! ✨ 🍰 ✨
1 file reformatted.
Der Unterschied zwischen Black und Flake8:
* Black ist ein Code-Formatter. Er formatiert Ihren Code um, sodass er im Einklang mit PEP 8 steht.
* Flake8 ist ein {{W|Lint (Programmierwerkzeug) | Code-Linter}}. Flake8 verändert Ihren Code nicht, sondern durchsucht ihn nach potenziellen Fehlern etc.
Am obigen Beispiel sieht man auch, dass flake8 und Black nicht immer einer Meinung sind. Flake8 (<code>flake8 test1.py</code>) würde standardmäßig den mit Black formatierten Code bemängeln:
test1.py:8:80: E501 line too long (80 > 79 characters)
Diese Diskrepanz kann beseitigt werden. Da 79 Zeichen auf modernen Bildschirmen meist als zu kurz empfunden werden, ist ein Limit von 88 Zeichen (Black-Standard) oder mehr empfehlenswert. Um dies zu implementieren, erstellen Sie in Ihrem Projektverzeichnis eine <code>.flake8</code>-Datei mit dem Inhalt
[flake8]
max-line-length = 88
Und schon ignoriert Flake8 dieses Problem.
Ein anderer Linter ist pylint. Der würde beim Abarbeiten des obigen Beispiels, z.B. mit <code>pylint test1.py</code> noch eine Kleinigkeit bemängeln:
************* Module test1
/home/hr/tmp/test1.py:1:0: C0114: Missing module docstring (missing-module-docstring)
------------------------------------------------------------------
Your code has been rated at 8.57/10 (previous run: 8.57/10, +0.00)
Auch pylint muss vor der ersten Verwendung installiert werden (z.B. mittels pip, virtuelle Umgebung, YaST). Die Dokumentation zu pylint findet sich auf [https://pylint.readthedocs.io/en/latest/].
<u>Aufgabe:</u> Fügen Sie einen "module docstring" in die <code>test1.py</code>-Datei ein und testen Sie erneut mit flake8, Black und pylint. <small>Sehen Sie zum Thema docstrings auch [https://peps.python.org/pep-0257/#what-is-a-docstring PEP 257 – Docstring Conventions].</small>
Es gibt noch weitere Formatierungswerkzeuge für Python-Code. Z.B. [https://docs.astral.sh/ruff/ Ruff], ein moderner Code-Formatter und -Linter. Mittels <code>ruff check test1.py</code> würde obiger Code geprüft (Linter). <code>ruff format test1.py</code> formatiert den Code (Formatter).
== Type Checker ==
"Type Checker" sind z.B.
* mypy
* pyright
* ty
Diese prüfen die Datentypen, z.B. in folgendem Code
def greetings(name: str) -> str:
return "Hello, %s" % name
print(greetings(42))
Python selbst, flake8, ruff oder black würden diesen Code ohne zu murren akzeptieren. "Type Checker" würden aber sehr wohl Alarm schlagen, z.B. liefert <code>mypy</code> folgende Ausgabe
test1.py:5: error: Argument 1 to "greetings" has incompatible type "int"; expected "str" [arg-type]
Found 1 error in 1 file (checked 1 source file)
==pydoc==
pydoc ist ein Werkzeug, um Python-Module, -Funktionen und -Klassen zu dokumentieren.
Beispiel <code>test1.py</code>:
"""Rechen-Modul.
Funktionen die von pydoc gelesen werden.
"""
def multiply(a, b):
"""Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a * b
def add(a, b):
"""Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
"""
return a + b
if __name__ == '__main__':
print(multiply(3, 5))
print(add(4, 6))
Ausgabe mit <code>python3.13 -m pydoc test1</code> auf der Konsole:
Help on module test1:
NAME
test1 - Rechen-Modul.
DESCRIPTION
Funktionen die von pydoc gelesen werden.
FUNCTIONS
add(a, b)
Addiert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
multiply(a, b)
Multipliziert zwei Zahlen und gibt das Ergebnis zurück.
Argumente:
a -- erste Zahl
b -- zweite Zahl
FILE
/home/xyz/tmp/test1.py
Siehe zu diesem Thema z.B. auch [https://docs.python.org/3/library/pydoc.html]. Mittels <code>python3.13 -m pydoc -w test1</code> kann man auch eine HTML-Dokumentation erstellen.
Wofür <code>if __name__ == '__main__':</code> steht, siehe z.B. etwas später im Abschnitt [[Ing_Mathematik:_Python#Doctests]].
== Sonstige Tools ==
Andere Tools für die {{W|Statische Code-Analyse|statische Codeanalyse}}, die aber für Ingenieure weniger interessant sein dürften, sind z.B.
* Radon: Liefert verschiedene {{W|Softwaremetrik|Codemetriken}} (Komplexität, Wartbarkeitsindex ...)
* Bandit: Findet Sicherheitslücken
Tools für die {{W|Dynamisches Software-Testverfahren|dynamische Codeanalyse}}, z.B.:
* DynaPyt (Framework zur dynamischen Programmanalyse)
* cProfile (Profiler)
* Memory Profiler (Speicheranalyse)
* Memray (Speicheranalyse)
* tracemalloc (Speicheranalyse)
Paket- und Projektmanagement (pip-Ersatz etc.):
* uv
* Poetry
* Conda
* pipx
Packaging-Tools (Freezer) und {{W|Compiler#Sonderformen|Transpiler}} :
* pyinstaller
** erstellt eigenständige, ausführbare Binärdatei
** kein Cross-Compiler
** kein Schutz vor Reverse-Engineering
** langsam
** packt alles in eine Datei
** sehr große Datei
** Befehl, z.B.: <code>pyinstaller --onefile test1.py</code>
** GUI: <code>auto-py-to-exe</code>
* cx_Freeze
* nuitka
** Übersetzt Python-Code in C/C++-Code und weiter in eine ausführbare Datei
** kein Cross-Compiler
** Schutz vor Reverse-Engineering
** Befehl, z.B.: <code>nuitka --standalone --onefile test1.py</code>
* cython
= Einige Integrierte Entwicklungsumgebungen (IDEs)=
Werden Programmtexte größer und umfangreicher, so ist das Arbeiten mit der interaktiven Programmierumgebung bzw. das direkte Ausführen von Python-Skripten mühsam. Man wünscht sich z.B. Hilfen zum Debuggen oder die automatische Code-Vervollständigung. Zu diesem Zweck wurden IDEs (Integrated Development Environments) geschaffen. Von diesen seinen nachfolgend auszugsweise einige kurz beschrieben. Testen Sie einfach aus, welche davon für Sie bzw. für Ihr Python-Projekt geeignet sind.
== IDLE ==
IDLE ist die mit dem Python-Programmpaket mitgelieferte IDE. Der Name leitet sich einerseits ab vom Monty-Python-Mitglied Eric Idle, andererseits steht es als Abkürzung für "'''I'''ntegrated '''D'''evelopment and '''L'''earning '''E'''nvironment. IDLE ist einfach zu bedienen, bietet aber schon einen beachtlichen Leistungsumfang. Nachfolgend wird ein Screenshot zu IDLE geliefert. Rechts ist das Editor-Fenster zu sehen, links die interaktive Programmierumgebung. Um das Beispiel selbst nachvollziehen zu können, starten Sie IDLE. Das geht ähnlich, wie Sie die interaktive Programmierumgebung von Python starten (nur, dass Sie eben das IDLE-Icon doppelklicken und nicht das Python-Icon. Unter Linux geben Sie einfach in einem Terminal <code>idle3.13</code> o. Ä. ein). Weiter geht es mit "File - Open - ...". Die auszuführende Datei auswählen (im konkreten Fall ein "Hallo-Welt"-Programm). Es erscheint das rechte Fenster. Dort "Run - Run Module" auswählen. Und schon wird im linken Fenster "Hallo Welt!" ausgegeben.
[[Datei:PythonIng_idle1.jpg | 600px]]
Siehe auch {{W|IDLE}}.
== PyCharm ==
PyCharm ist ein kommerzielles Produkt. Es gab aber auch eine kostenlose Community Edition. Seit 2025 sind beide Varianten vereint. Für die ersten 30 Tage sind die Pro-Funktionen frei verfügbar, danach nur noch die Kernfunktionalitäten (oder man bezieht kostenpflichtig die Pro-Version). Zu beziehen ist PyCharm unter dem Weblink [https://www.jetbrains.com/pycharm/]. Nachfolgend ein etwas abgewandeltes "Hallo Welt"-Programm, editiert und ausgeführt mit PyCharm.
[[Datei:PyCharm_IDE_2023_screenshot.png | 600px]]
Siehe auch {{W|PyCharm}}.
== Eric ==
Auch eric ist Open Source und steht unter der GNU General Public License Version 3 oder später. Zu beziehen ist diese Software unter [https://eric-ide.python-projects.org/].
[[Datei:Screenshot_Eric_4.png | 600px]]
Siehe auch {{W|eric (Software)}}.
<small>
Unter openSUSE Tumbleweed sollte sich eric auch mit YaST installieren lassen. Bei mir gibt es aber dann beim Ausführen des eric-Programms eine Fehlermeldung (Stand März 2026):
...
ModuleNotFoundError: No module named 'PyQt6.QtPdfWidgets'
Umgehen kann man dieses Problem aber wieder mit dem Erstellen einer virtuellen Umgebung, in etwa so
python3.13 -m venv ~/tmp/venv1
cd ~/tmp/venv1/bin
./python3.13 -m pip install --upgrade --prefer-binary eric-ide
./eric7_ide
</small>
== PyScripter ==
Vom Funktionsumfang vergleichbar mit den vorherigen IDEs ist PyScripter. Auch PyScripter ist Open Source. Die Projekt-Homepage findet sich auf [https://sourceforge.net/projects/pyscripter/]. PyScripter ist nur für MS Windows verfügbar.
[[Datei:PythonIng_pyscripter1.jpg | 600px]]
== Spyder IDE ==
Spyder enthält bereits eine stabile Python-Version und etliche Module (z.B. matplotlib, numpy, control). Ansonsten kann dieses Softwarepaket vom Funktionsumfang her mit den anderen genannten IDEs locker mithalten. Spyder wurde unter der MIT-Lizenz veröffentlicht. Diese Software findet sich auf [https://www.spyder-ide.org].
[[Datei:Spyder-windows-screenshot.png | 600px]]
Siehe auch {{W|Spyder (Software)}}
== Eclipse IDE==
Die {{W|Eclipse_(IDE)|Eclipse-IDE}} kann für Python aufgerüstet werden. Dazu gibt es das PyDev-Plugin. Installiert wird es über
* Help > Eclipse Marketplace...
* Find - PyDev - Install
Danach muss noch der Pfad zum Python-Interpreter festgelegt werden
* Window > Preferences > PyDev > Interpreters > Python Interpreter > New ...
Das Ergebnis ist ähnlich wie im folgenden Bild, nur dass statt C/C++ Python Verwendung findet.
[[Datei:Setting Up Eclipse CDT helloout.png | 600px]]
== Sonstige ==
Die genannten IDEs sind nicht die Einzigen. Es gibt, um dem Image Pythons als beliebteste Programmiersprache gerecht zu werden, noch einige andere. Sowohl Open Source-Programme als auch kommerzielle Programme sind im Web zu finden, z.B. Thonny oder {{W|Visual Studio Code}}. Unter Linux kann man auch {{W|KDevelop}}, ausgestattet mit dem Python3-Plugin, einsetzen. Braucht man den Umfang von ausgewachsenen IDEs nicht, so kann man auch normale Texteditoren verwenden (z.B. {{W|Geany}} oder {{W|Kate_(Texteditor)|Kate}}).
= Debuggen und Testen =
Das Debuggen und Testen von Programmen sind wichtige Bestandteile der Programmierung. Syntaxfehler lassen sich i.A. leicht beheben. Schwieriger ist das Eingrenzen von logischen Fehlern, die ev. nur in bestimmten Situationen auftreten und keine explizite Fehlermeldung hervorrufen. Das Programm liefert falsche Ergebnisse oder es stürzt aus heiterem Himmel ab. Um das zu verhindern gibt es verschiedene Werkzeuge, die bei der Fehlersuche behilflich sein können. Vorerst siehe aber zwecks Begriffsklärung noch folgende Links:
* {{W|Debuggen}}
* {{W|Debugger}}
* {{W|Softwaretest}}
<gallery>
First Computer Bug, 1947.jpg
Test ganzheitlich.png
V-Modell.svg
</gallery>
== Das Modul pdb ==
Python bringt schon ein Modul zum Debuggen mit. Siehe z.B. [https://docs.python.org/3/library/pdb.html pdb — The Python Debugger].
Komfortabler lässt sich das aber mittels Integrierter Entwicklungsumgebungen (IDEs) angehen.
== Debuggen mit IDEs ==
Für die IDEs IDLE und Spyder sei kurz auf die entsprechenden Webseiten verwiesen:
* [https://www.cs.uky.edu/~keen/help/debug-tutorial/debug.html Debugging under IDLE].
* [https://docs.spyder-ide.org/current/panes/debugging.html Spyder Debugger]
Dort wird die Vorgehensweise auch mittels Screenshots erläutert.
== assert ==
assert ... behaupten, zusichern ({{W|Assertion (Informatik)}})
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10., 0.)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10., 0.)
File "/home/hr/Develop/test1.py", line 4, in print1
assert y != 0.0
^^^^^^^^
AssertionError
Python-Code:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1("10.", "5.")
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Aber auch bei nachfolgendem Code gibt es eine Fehlermeldung:
def print1(x, y):
assert type(x) == float
assert type(y) == float
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
Traceback (most recent call last):
File "/home/hr/Develop/test1.py", line 8, in <module>
print1(10, 5)
File "/home/hr/Develop/test1.py", line 2, in print1
assert type(x) == float
^^^^^^^^^^^^^^^^
AssertionError
Damit letzteres funktioniert, kann man den Programmcode so umschreiben:
def print1(x, y):
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
print1(10., 5.)
print1(10, 5)
Ausgabe:
2.0
2.0
Und jetzt fangen wir den <code>AssertionError</code> auf:
def print1(x, y):
try:
assert type(x) == float or type(x) == int
assert type(y) == float or type(y) == int
assert y != 0.0
print(x/y)
except(AssertionError):
print("Hallo")
print1(10., 5.)
print1("10.", "5.")
Ausgabe:
2.0
Hallo
Ich hoffe, es ist wenigstens im Ansatz klar geworden, wofür <code>assert</code> gut sein kann. Ausschalten kann man die <code>assert</code>-Überprüfung übrigens mit dem Python-Schalter <code>-O</code>.
== Doctests ==
Innerhalb eines Docstrings kann die Arbeit im interaktiven Modus simuliert werden. Nach den Promptzeichen (>>>) erfolgen dann bei unserem Beispiel innerhalb des Docstrings simulierte Aufrufe der Funktion <code>print1()</code>. Danach folgen jeweils die Sollresultate. Wird das Modul oder die Datei als Hauptprogramm aufgerufen, so wird die Funktion <code>doctest.testmode()</code> aufgerufen und ein Bericht auf der Konsole ausgegeben. Wird das Modul nicht als Hauptprogramm aufgerufen, sondern importiert, dann wird diese <code>testmod</code>-Funktion nicht aufgerufen. D.h. dieser Code kann sowohl für Testzwecke als auch für den produktiven Einsatz verwendet werden. Das ist auch sinnvoll, weil wenn man Teile der Datei immer löschen bzw. einfügen müsste, so würden sich Fehlerquellen auftun. Das würde den Sinn und Zweck von Doctests konterkarieren.
def print1(x=0., y=1.):
""" Dividiere zwei Zahlen
Autor: Intruder
Datum: 12.08.2025
>>> print1(2., 1.)
2.0
>>> print1(5., 2.)
2.5
>>> print1(5.)
5.0
"""
print(x/y)
if __name__ == "__main__":
import doctest
doctest.testmod(verbose=True)
Ausgabe:
Trying:
print1(2., 1.)
Expecting:
2.0
ok
Trying:
print1(5., 2)
Expecting:
2.5
ok
Trying:
print1(5.)
Expecting:
5.0
ok
1 items had no tests:
__main__
1 items passed all tests:
3 tests in __main__.print1
3 tests in 2 items.
3 passed and 0 failed.
Test passed.
Das gezeigte Beispiel ist so ziemlich das einfachste, das es gibt. Für weiterführende Details siehe z.B.:
* [https://peps.python.org/pep-0257/ PEP 257 – Docstring Conventions]
* [https://docs.python.org/3/library/doctest.html doctest — Test interactive Python examples]
''Einschub:'' Ganz ähnlich kann man auch Klassen testen, z.B. in folgendem Code-Fragment
class Fahrzeug:
# siehe Abschnitt "Objektorientierte Programmierung"
# ...
if __name__ == "__main__":
vauweh = Fahrzeug(170, 90)
beemweh = Fahrzeug(200, 120)
print(vauweh.convertGeschw())
print(beemweh.convertGeschw())
Wird das Script als Hauptprogramm ausgeführt (z.B. zu Testzwecken), so erfolgt die Ausgabe der zwei, via <code>convertGeschw()</code>, umgerechneten Geschwindigkeiten. Wird es aber als Modul eingebunden, so wird der letzte Programmabschnitt nicht ausgeführt (<code>__name__ == "__main__"</code> ergibt <code>False</code>).
== pytest ==
Siehe zu diesem Thema auch {{W|Modultest}}.
pytest ist ein externes Modul und muss vorab installiert werden, z.B. mittels
pip install -U pytest
pip install -U pytest-html
Python-Code, Datei test1.py:
def add(x, y):
return x + y
def test_answer():
assert add(1, 1) == 3
Starten von pytest in der Konsole:
pytest test1.py
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py F [100%]
========================================================= FAILURES ==========================================================
________________________________________________________ test_answer ________________________________________________________
def test_answer():
> assert add(1, 1) == 3
E assert 2 == 3
E + where 2 = add(1, 1)
test1.py:6: AssertionError
================================================== short test summary info ==================================================
FAILED test1.py::test_answer - assert 2 == 3
===================================================== 1 failed in 0.09s =====================================================
Hier erhalten wir einen Fehler, da 1+1 eindeutig ungleich 3 ist. Aber aus irgendeinem Grund wollte der Programmierer oder Tester in diesem Fall, dass dies so ist. Testfälle werden übrigens mit dem Präfix <code>test_</code> eingeleitet.
Python-Code:
def add(x, y):
return x + y + 1
def test_answer():
assert add(1, 1) == 3
Ausgabe:
==================================================== test session starts ====================================================
platform linux -- Python 3.12.11, pytest-8.4.1, pluggy-1.6.0
rootdir: /home/hr/Develop
plugins: anyio-4.10.0, metadata-3.1.1, html-4.1.1
collected 1 item
test1.py . [100%]
===================================================== 1 passed in 0.01s =====================================================
Jetzt ist alles in Ordnung. Weiterführendes siehe z.B.
* [https://docs.pytest.org/en/stable/ pytest: helps you write better programs]
== unittest ==
Auch unittest dient zur Durchführung von Testreihen, ist aber Bestandteil von Python. Hier wird vorerst nicht näher darauf eingegangen. Siehe z.B.
* [https://docs.python.org/3/library/unittest.html unittest — Unit testing framework]
Lt. ''Inden: Python Challenge; dpunkt, 2021, Seite 481'' soll unittest weniger komfortabel als pytest sein.
Einen Vergleich von unittest mit pytest findet man in
* [https://knapsackpro.com/testing_frameworks/difference_between/pytest/vs/unittest pytest vs unittest]
= Python und Anwendungsprogramme =
Bisher stand immer alleine die Programmiersprache Python (ev. unter Einbeziehung von Modulen) im Mittelpunkt der Betrachtungen. Aber Python kann auch als Makrosprache für Anwendungsprogramme auftreten. Als Beispiele seien {{W|FreeCAD}} und {{W|LibreOffice}} genannt.
== FreeCAD ==
FreeCAD ist ein freies 3D-CAD-Programm. Hier soll nicht auf die Bedienung dieses CAD-Pakets eingegangen werden, sondern nur auf die Möglichkeit, mittels Python Makros zu schreiben. Als einfacher Einstieg soll ein Makro erstellt werden, welches eine Kugel (rot) und einen Quader (blau) zeichnet. Folgende Vorbereitungsschritte sind erforderlich (es sei vorausgesetzt, dass FreeCAD schon am Rechner installiert ist. Downloaden können Sie das Programm von der Website [https://www.freecad.org/downloads.php?lang=en]):
* FreeCAD starten
* Leere Datei erstellen
* Makro > Makros > Erstellen ...
Es öffnet sich ein leeres Editorfenster, in das Sie folgenden Code eingeben können:
import FreeCAD
import Part
doc = FreeCAD.newDocument()
# Kugel
kugel = Part.makeSphere(10)
form_element = doc.addObject("Part::Feature", "Kugel")
form_element.Shape = kugel
kug = FreeCAD.ActiveDocument.getObject("Kugel")
kug.ViewObject.ShapeColor = (1.0, 0.0, 0.0)
neuePosition = App.Vector(5, 2.5, 2.5)
kug.Placement = App.Placement(neuePosition, kug.Placement.Rotation)
# Quader
quader = Part.makeBox(5, 5, 50)
form_element = doc.addObject("Part::Feature", "Quader")
form_element.Shape = quader
quad = FreeCAD.ActiveDocument.getObject("Quader")
quad.ViewObject.ShapeColor = (0.0, 0.0, 1.0)
doc.recompute()
Diesen Code können Sie nun ausführen:
* Makro > Makro ausführen
Es ergibt sich folgende Ausgabe (gedreht und gezoomt):
[[Datei: PythonIng_freecad1.png|500px]]
Siehe auch [https://wiki.freecad.org/Python_scripting_tutorial/de# Anleitung Skripterstellung mit Python]. Getestet wurde obiges Beispiel mit FreeCAD 1.1.3 unter Linux und 1.1.1 unter MS Windows.
== LibreOffice ==
LibreOffice ist ein freies Officepaket ([https://de.libreoffice.org/]). Hier soll nur das Tabellenkalkulationsprogramm Calc kurz betrachtet werden. Es seinen in den ersten 3 Zellen (A1 bis A3) Zahlen gegeben. Diese sollen mit einem Python-Makro addiert und das Resultat in der Zelle A5 ausgegeben werden. Auch hier sind Vorbereitungsarbeiten nötig:
* zuerst muss unter Linux das Verzeichnis <code>~/.config/libreoffice/4/user/Scripts/python</code> erstellt werden
* für MS Windows ist es das Verzeichnis <code>%APPDATA%\LibreOffice\4\user\Scripts\python</code>
** drücken Sie zuerst Win + R (es öffnet sich das Ausführen-Fenster)
** geben Sie <code>%appdata%</code> ein, danach drücken Sie Enter (es öffnet sich der Explorer)
** navigieren Sie zu dem genannten Verzeichnis bzw. erstellen Sie das Verzeichnis
* in diesem Verzeichnis wird dann mit einem beliebigen Texteditor das Python-Makro erstellt, in unserem Fall die Datei <code>summiere_zellen.py</code>:
import uno
def summiere_zellen(*args):
# Zugriff auf das aktuelle Dokument und das aktive Tabellenblatt
ctx = uno.getComponentContext()
smgr = ctx.getServiceManager()
desktop = smgr.createInstanceWithContext("com.sun.star.frame.Desktop", ctx)
doc = desktop.getCurrentComponent()
sheet = doc.getCurrentController().getActiveSheet()
# Werte aus den Zellen A1 bis A3 auslesen
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
# Addition der drei Werte
summe = w1 + w2 + w3
# Ergebnis in die Zelle A5 schreiben
sheet.getCellRangeByName("A5").Value = summe
* siehe dazu ggf. auch [https://help.libreoffice.org/latest/de/text/sbasic/python/python_locations.html?DbPAR=BASIC].
Weiter geht es in LibreOffice Calc mit dem Menü ''Extras > Makros > Makros verwalten > Python''. Dort wird das Makro <code>summiere_zellen</code> ausgeführt. Es ergibt sich z.B. folgendes Resultat
[[Datei:PythonIng_libreoffice1.png]]
Das Kürzel <code>uno</code> steht für '''U'''niversal '''N'''etwork '''O'''bjects. Etwas einfacher geht's auch so:
def summiere_zellen():
desktop = XSCRIPTCONTEXT.getDesktop()
model = desktop.getCurrentComponent()
sheets = model.getSheets()
sheet = sheets.getByIndex(0)
w1 = sheet.getCellRangeByName("A1").Value
w2 = sheet.getCellRangeByName("A2").Value
w3 = sheet.getCellRangeByName("A3").Value
cell = sheet.getCellRangeByName("A5")
cell.setValue(w1 + w2 + w3)
Empfohlen wird auch, das Erweiterungspaket APSO ('''A'''lternative '''P'''ython '''S'''cript '''O'''rganizer, apso.oxt) zu installieren. Die Vorgehensweise wird hier nicht gezeigt, sondern nur darauf hingewiesen, dass man das einfach "googeln" kann. Siehe zur Python-Programmierung für LibreOffice auch [https://wiki.documentfoundation.org/Macros/Python_Guide/de Makros/Python-Handbuch]. Getestet wurden obige Beispiele mit LibreOffice 26.2.5.1 unter Linux und 26.2.1.2 unter MS Windows.
= Ausblick =
Dies war eine kurze Einführung in die Berechnungs- und Darstellungsmöglichkeiten mit Python. Es sollten etliche relevante Themen behandelt, oder zumindest kurz angesprochen worden sein. Wem dieser Text nicht ausreichend ist, der sei auf die entsprechenden weiterführenden Weblinks, Bücher und die Python-Hilfefunktion verwiesen. Python kennt noch viel mehr Befehle, als hier dargestellt wurden. Das Themenspektrum ist auch durch die Einbindung externer Module fast beliebig erweiterbar.
= Weblinks=
== Python allgemein ==
* [https://www.python.org/ Python Homepage]
== Externe mathematische Module ==
* [https://numpy.org/ NumPy]
* [https://numpy.org/doc/stable/user/numpy-for-matlab-users.html NumPy for MATLAB users]
* [https://scipy.org/ SciPy]
* [https://www.sympy.org/en/index.html SymPy]
* [https://pandas.pydata.org/ pandas]
* [https://github.com/maroba/findiff findiff]
* [https://mpmath.org/ mpmath]
== Externe Module für Grafiken ==
* [https://matplotlib.org/ Matplotlib]
* [https://vpython.org/ VPython]
* [https://docs.vtk.org/en/latest/api/python.html VTK]
== Erstellung von User Interfaces ==
* [https://docs.python.org/3/library/tkinter.html tkinter - Python interface to Tcl/Tk]
* [https://docs.python.org/3/library/curses.html curses - Terminal handling for character-cell displays]
* [https://wiki.qt.io/Qt_for_Python Qt for Python]
* [https://www.gtk.org/docs/language-bindings/python GTK and Python]
== Erstellen virtueller Umgebungen ==
* [https://docs.python.org/3/library/venv.html venv - Creation of virtual environments]
== Sonstige ==
* [https://python-control.readthedocs.io/en/stable/ Python Control Systems Library]
* [https://pypi.org/project/regex/ regex - Regular Expressions]
* [http://pyromat.org/ PYroMat]
* [https://coolprop.org/coolprop/wrappers/Python/index.html CoolProp]
* [https://pypi.org/project/iapws/ iapws]
* [https://tespy.readthedocs.io/en/main/getting_started/introduction.html TESPy - Thermal Engineering Systems in Python]
= Bücher =
== Gedruckte Bücher, OpenBooks, Magazine ==
* Diverse: c't Python Lernen, Verstehen, Anwenden; Heise, 2022
* Ernesti, Kaiser: Python3 - das umfassende Handbuch; 5. Aufl., Rheinwerk, [https://openbook.rheinwerk-verlag.de/python/ OpenBook]
* Inden: Python Challenge; dpunkt, 2021, ISBN 978-3-86490-809-5
* Klein: Numerisches Python; 2. Aufl., Hanser, 2023, ISBN 978-3-446-47170-2
* Steinkamp: Der Python-Kurs für Ingenieure und Naturwissenschaftler; Rheinwerk, 2021, ISBN 978-3-8362-7316-9
* Weigend: Python 3 - Das umfassende Praxisbuch; 9. Aufl., mitp, 2022, ISBN 978-3-7475-0544-1
* Woyand: Python für Ingenieure und Naturwissenschaftler; 4. Aufl., Hanser, 2021, ISBN 978-3-446-46483-4
== Andere Wikibooks ==
* [[:en:Subject:Python_programming_language | Englische Wikibooks zum Thema Python]]
* [[Python|Deutschsprachiges Python-Wikibook]] [[Bild:2von10.png|20%]]
* [[Python unter Linux|Python 2.7 unter Linux]] [[Bild:10von10.png|100%]]
{{Navigation_zurückhochvor_buch|
zurücktext=Julia für Ingenieure|
zurücklink=Ing Mathematik: Julia|
hochtext=Gesamtinhaltsverzeichnis|
hochlink=Ing:_Mathematik_für_Ingenieure|
vortext=Landau-Notation|
vorlink=Ing Mathematik: Landau}}
nmqqeonbb6zmlu3os738jmoeuwbtca5
Programmieren in C/C++: Grundlagen
0
118048
1090621
1090612
2026-09-09T12:54:18Z
D. Justen
102048
Formulierungen entsprechend der Rückmeldungen aus den letzten Vorlesungen angepasst
1090621
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
Zahlenwerte und Strings im Source-Code werden vom Compiler in binäre Zahlen umgerechnet. Über der Schreibweise/Syntax der Literale/Konstanten wird dem Compiler gesagt, in welchem Zahlenformat die Zahl auf Source-Code Ebene beschrieben ist und welchem Datentyp sie entspricht.
Unabhängig wie die Konstanten im Source-Code beschrieben sind, werden die Zahlen intern als binäre Zahlen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner
Nur in C++ Spezifikation enthalten
ab C23-Spezifikation auch im C-Syntax enthalten.
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Konform zur C-Spezifikation bieten einige Compiler weitere Operatoren aus der math.h Library an (z.B. sin(), cos(), ...). Bestehen die Aufrufparameter aus Konstanten, so ersetzt der Compiler den Ausdruck durch die 'Ergebnis'-Konstante:
:<syntaxhighlight lang="C">
int var3=sin(1.0)*10; →wird vom Compiler durch 8 ersetzt
</syntaxhighlight>
* Konstanten Ausdrücke werden durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert, so dass bspw.:
:<syntaxhighlight lang="C">
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit auch innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann ergänzend auf Variablen des umgebenden Blockes zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void).<br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]).
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo;
fptr();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (nicht C++), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func() {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern beliebige Ausdrücke erlaubt sind. Der resultierende Datentyp des Ausdruckes muss letztendlich dem Rückgabedatentyp der Funktion entsprechen:
<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Bereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Als Parameter können Strings übergeben werden, welche in Form eines Arrays von Strings übergeben werden. Im Parameter argc sind die Anzahl der Strings enthalten. Im Parameter argv[x] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder ungleich 0 fehlerhafte Ausführung). Der Start der Anwendung kann als Funktionsaufruf angesehen werden, welchen einen Wert an den Aufrufer zurückliefert.
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Inline erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline funktioniert, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass anstatt der … Anweisung, beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der übergebenen Datentype der Parameter wird der aufgerufenen Funktion nicht mitgeteilt! Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, muss dies am Beispiel der <code>printf</code> Funktion über den Format-String erfolgen:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value | Discarded Value]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
ccg680s5eq12xyq3ou0euwoa7pkp7aj
1090622
1090621
2026-09-09T12:55:23Z
D. Justen
102048
Link angepasst
1090622
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
Zahlenwerte und Strings im Source-Code werden vom Compiler in binäre Zahlen umgerechnet. Über der Schreibweise/Syntax der Literale/Konstanten wird dem Compiler gesagt, in welchem Zahlenformat die Zahl auf Source-Code Ebene beschrieben ist und welchem Datentyp sie entspricht.
Unabhängig wie die Konstanten im Source-Code beschrieben sind, werden die Zahlen intern als binäre Zahlen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner
Nur in C++ Spezifikation enthalten
ab C23-Spezifikation auch im C-Syntax enthalten.
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Konform zur C-Spezifikation bieten einige Compiler weitere Operatoren aus der math.h Library an (z.B. sin(), cos(), ...). Bestehen die Aufrufparameter aus Konstanten, so ersetzt der Compiler den Ausdruck durch die 'Ergebnis'-Konstante:
:<syntaxhighlight lang="C">
int var3=sin(1.0)*10; →wird vom Compiler durch 8 ersetzt
</syntaxhighlight>
* Konstanten Ausdrücke werden durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert, so dass bspw.:
:<syntaxhighlight lang="C">
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit auch innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann ergänzend auf Variablen des umgebenden Blockes zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void).<br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]).
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo;
fptr();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (nicht C++), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func() {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern beliebige Ausdrücke erlaubt sind. Der resultierende Datentyp des Ausdruckes muss letztendlich dem Rückgabedatentyp der Funktion entsprechen:
<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Bereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Als Parameter können Strings übergeben werden, welche in Form eines Arrays von Strings übergeben werden. Im Parameter argc sind die Anzahl der Strings enthalten. Im Parameter argv[x] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder ungleich 0 fehlerhafte Ausführung). Der Start der Anwendung kann als Funktionsaufruf angesehen werden, welchen einen Wert an den Aufrufer zurückliefert.
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Inline erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline funktioniert, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass anstatt der … Anweisung, beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der übergebenen Datentype der Parameter wird der aufgerufenen Funktion nicht mitgeteilt! Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, muss dies am Beispiel der <code>printf</code> Funktion über den Format-String erfolgen:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
fm2vpvi7vpcslvon5v40m8215203pyg
1090628
1090622
2026-09-09T17:55:23Z
D. Justen
102048
An wenigen Stellen Formulierungen angepasst und Kapitel 'Funktionen in Funktionen' eingefügt
1090628
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
Zahlenwerte und Strings im Source-Code werden vom Compiler in binäre Zahlen umgerechnet. Über der Schreibweise/Syntax der Literale/Konstanten wird dem Compiler gesagt, in welchem Zahlenformat die Zahl auf Source-Code Ebene beschrieben ist und welchem Datentyp sie entspricht.
Unabhängig wie die Konstanten im Source-Code beschrieben sind, werden die Zahlen intern als binäre Zahlen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner
Nur in C++ Spezifikation enthalten
ab C23-Spezifikation auch im C-Syntax enthalten.
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Konform zur C-Spezifikation bieten einige Compiler weitere Operatoren aus der math.h Library an (z.B. sin(), cos(), ...). Bestehen die Aufrufparameter aus Konstanten, so ersetzt der Compiler den Ausdruck durch die 'Ergebnis'-Konstante:
:<syntaxhighlight lang="C">
int var3=sin(1.0)*10; →wird vom Compiler durch 8 ersetzt
</syntaxhighlight>
* Konstanten Ausdrücke werden durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert, so dass bspw.:
:<syntaxhighlight lang="C">
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (nicht C++), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
1h9h7ogz7hkjcstvck7t49o0l5gt4xm
1090644
1090628
2026-09-10T08:37:09Z
D. Justen
102048
C23 Eigenschaft eingearbeitet
1090644
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
Zahlenwerte und Strings im Source-Code werden vom Compiler in binäre Zahlen umgerechnet. Über der Schreibweise/Syntax der Literale/Konstanten wird dem Compiler gesagt, in welchem Zahlenformat die Zahl auf Source-Code Ebene beschrieben ist und welchem Datentyp sie entspricht.
Unabhängig wie die Konstanten im Source-Code beschrieben sind, werden die Zahlen intern als binäre Zahlen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner
Nur in C++ Spezifikation enthalten
ab C23-Spezifikation auch im C-Syntax enthalten.
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Konform zur C-Spezifikation bieten einige Compiler weitere Operatoren aus der math.h Library an (z.B. sin(), cos(), ...). Bestehen die Aufrufparameter aus Konstanten, so ersetzt der Compiler den Ausdruck durch die 'Ergebnis'-Konstante:
:<syntaxhighlight lang="C">
int var3=sin(1.0)*10; →wird vom Compiler durch 8 ersetzt
</syntaxhighlight>
* Konstanten Ausdrücke werden durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert, so dass bspw.:
:<syntaxhighlight lang="C">
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
2j5wqr34tnl1afwbik7rvowowt7z8l7
1090652
1090644
2026-09-10T10:16:40Z
D. Justen
102048
Einführung, Tausendertrenner, Konstantenausdrücke aktualisiert
1090652
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert, so dass bspw.:
:<syntaxhighlight lang="C">
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
7dx8adfbs0omfsq2svrclfi2q0e9593
1090654
1090652
2026-09-10T10:58:09Z
D. Justen
102048
Satzstellung korrigiert
1090654
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert:
:<syntaxhighlight lang="C">
//Quelle: C-Spec Kap. 6.5.2.2 entnommen
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
//Quelle: C-Spec Kap. 6.5.2.2 entnommen
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
qfmhnjtxifqwrt6itkrf9swtzqgehlx
1090655
1090654
2026-09-10T10:59:37Z
D. Justen
102048
Wort entommen entfernt
1090655
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert:
:<syntaxhighlight lang="C">
//Quelle: C-Spec Kap. 6.5.2.2
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
//Quelle: C-Spec Kap. 6.5.2.2
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu. Ergänzend dient der L-Value als Rückgabewert des Operators, so dass das Ergebnis der Zuweisung weiter genutzt werden kann.
Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
akrszaqskl2eohlqgyqssa1ivdu2ga0
1090656
1090655
2026-09-10T11:24:59Z
D. Justen
102048
Beschreibung verbessert und Beispiel ergänz
1090656
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert:
:<syntaxhighlight lang="C">
//Quelle: C-Spec Kap. 6.5.2.2
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
//Quelle: C-Spec Kap. 6.5.2.2
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung (<code>=</code>-Operator, assignment expression) weist dem L-Value den R-Value zu.
Der Zuweisungs-Operator gibt den L-Value als Rückgabewert Zuweisung zurück, so mehrere Zuweisungen in einem Ausdruck möglich sind. Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
9xjf72m29d7ectkqjjuf34phvrzvt51
1090657
1090656
2026-09-10T11:26:52Z
D. Justen
102048
Fehlende Wörter ergänz
1090657
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert:
:<syntaxhighlight lang="C">
//Quelle: C-Spec Kap. 6.5.2.2
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
//Quelle: C-Spec Kap. 6.5.2.2
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung ('='-Operator, assignment expression) weist dem L-Value den R-Value zu.
Der Zuweisungs-Operator gibt den L-Value als Rückgabewert der Zuweisung zurück, so dass mehrere Zuweisungen in einem Ausdruck möglich sind. Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungsoperator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
lwqqnvgd71uh5jde14d82n01iz9cw60
1090658
1090657
2026-09-10T11:28:40Z
D. Justen
102048
Rechtschreibung
1090658
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert:
:<syntaxhighlight lang="C">
//Quelle: C-Spec Kap. 6.5.2.2
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
//Quelle: C-Spec Kap. 6.5.2.2
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung ('='-Operator, assignment expression) weist dem L-Value den R-Value zu.
Der Zuweisungs-Operator gibt den L-Value als Rückgabewert der Zuweisung zurück, so dass mehrere Zuweisungen in einem Ausdruck möglich sind. Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungs-Operator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da Komma Bestandteil der Definition ist
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
hupxn6t08qret926b3padso3591iwiz
1090659
1090658
2026-09-10T11:37:01Z
D. Justen
102048
Formulierung geändert
1090659
wikitext
text/x-wiki
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
<!-- Falls du ein automatisch erstelltes Inhaltsverzeichnis nicht willst, ersetze das nachfolgende TOC durch NOTOC -->
<!-- Einklammerung mit noinclude, damit dieses nicht in der Druckversion erscheint -->
<noinclude>__TOC__</noinclude>
Die Programmiersprache C/C++ beinhaltet mehrere Sprachen/ Syntaxen:
* C-Syntax
* Präprozessor-Syntax
* Printf/Scanf Formatstring Syntax
* Terminal Emulation
* Compiler/Linker Anweisungen
Letztere beiden werden nur rudimentär in dieser Vorlesung/diesem Skript behandelt. Alle anderen sind Bestandteil dieser Vorlesung.
In diesem Kapitel sollen zunächst allgemeine Eigenschaften der Sprache, der grundlegende Syntax und die Kontrollstrukturen erklärt werden. Bei vielen Erklärungen sind Code-Beispiele vorhanden. Da man aus Fehlern am meisten lernt, sind zum Teil auch negative Beispiele enthalten. Für ein besseres Verständnis empfiehlt es sich, Code-Beispiele selbst nachzuvollziehen.<br />
Sofern sich die Eigenschaften auf eine bestimmte C-/C++- oder Compiler-Version beziehen, wird dies gesondert vermerkt.
== Zeichensatz ==
Der Syntax von C nutzt die unteren 128 Zeichen des ASCII Zeichensatzes. Da UTF-8 in den ersten 128 Zeichen deckungsgleich zu ASCII ist, kann auch dieser zur Erstellung des Source Codes genutzt werden.
Zeichen außerhalb dieses gültigen Zeichensatzes können folglich nur in Strings oder Kommentaren vorkommen. Werden Zeichen außerhalb der unteren 128 Zeichen in Strings genutzt, so gilt Folgendes zu berücksichtigen:
* Die String-Funktionalitäten der Standard-C Library gehen von dem regulären ASCII Zeichensatz aus, so dass z.B. die Suche, der Vergleich oder die Konvertierung fehlschlagen kann
* Strings werden oftmals in Verbindung mit printf() genutzt, d.h. auf der Standardausgabe ausgegeben. Der verwendete Zeichensatz sollte hier identisch zum verwendeten Zeichensatz der Terminal-Emulation sein!
== Kommentarzeichen ==
Kommentare dienen dazu, den Source Code mit zusätzlichen Hinweisen zu versehen, so dass die Intension der Anweisungen sichtbar wird. Kommentarzeichen werden durch den Compiler vor dem eigentlichen Übersetzungsdurchlauf entfernt und durch ein Leerzeichen ersetzt [C11 6.4.9]. Innerhalb von Strings wird nicht nach Kommentarzeichen gesucht.
<code>
Syntax: /* */
</code>
Blockkommentar zum Kommentieren eines Bereiches, auch über mehrere Zeilen hinweg. Dieses Kommentarzeichen kann nicht verschachtelt werden, d.h. '*/' beendet die Kommentierung, unabhängig von der Anzahl der zuvor geöffneten Kommentierungen!
<code>
Syntax: //
</code>
Zeilenkommentar zum Kommentieren bis zum Zeilenende (wurde in der Programmiersprache BCPL definiert, aber nicht von C, sondern erst von C++ übernommen).
Sollen größere Bereiche auskommentiert werden, so empfiehlt sich die Nutzung der Präprozessoranweisung #if 0 ... #endif.
Beispiele:
<syntaxhighlight lang="C">
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
/* Blockkommentar mit zwei öffnenden Klammern /*
über mehrere Zeilen, nicht verschachtelt
Compiler-Warning nur aufgrund des Compiler-Schalters -Wall! */
//Zeilenkommentar
/* Kleiner Bereich zum auskommentieren */
#if 0
Großer Bereich zum auskommentieren
#endif
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Namenskonventionen ==
Folgende Regeln gelten bzgl. der Benennung von Variablen und Funktionen:
* Variablen und Funktionsnamen können aus Buchstaben, Zahlen und dem Unterstrich bestehen. Sie müssen mit einem Buchstaben oder einem Unterstrich beginnen
* Seit C95 können weitere Zeichen aus dem Universal Coded Character Set (UCS) genutzt werden [C11 D.1]
* C ist Case sensitiv, d.h. es wird zwischen Groß- und Kleinbuchstaben unterschieden
* Schlüsselwörter können nicht für Variablen/Funktionsnamen/Datentypen genutzt werden
Namenskonventionen von Libraryfunktionen:
* In C (und C++) sind Schlüsselwörter und Standardlibraryfunktionen zumeist in Kleinbuchstaben geschrieben. In der C-Standardlibrary werden oftmals verkürzte Ausdrücke (z.B. isalnum() (zum Testen ob ein Zeichen ein Buchstaben oder ein Digit ist) und in C++ der Unterstrich als Worttrenner (z.b. out_of_range) genutzt
* Makros (siehe Kap.[[Programmieren in C/C++: Präprozessor | Präprozessor]]) werden per Konvention in GROSSBUCHSTABEN und ggf. mit Unterstrich als Worttrenner geschrieben.
* Namen beginnend mit doppelten Unterstrich oder beginnend mit einem Unterstrich gefolgt von einem Großbuchstaben (z.B. __LINE__ _Reserved) sind für den Compiler und der Standard-C-Library vorbehalten und sollten im eigenen Programm nicht benutzt werden.
== Zeilenfortsetzung ==
Mit dem Backslash Operator (gefolgt von einem Zeilenende) kann eine Zeile in der nächsten Zeile fortgesetzt werden. Der Compiler löscht das \-Zeichen mit anschließendem Zeilenende und ersetzt dies durch nichts. Dies ist insbesondere bei Anweisungen notwendig, die am Ende der Zeile abgeschlossen sein müssen (z.B. Strings, Makros).
Beispiele:
<syntaxhighlight lang="c">
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
char str1[]="Strings müssen am Ende abgeschlossen sein
so dass dies ein Fehler ist";
char str2[]="Dies\
ist ein Test"; //Vorsicht, führende Leerzeichen vor 'ist'
//bleiben erhalten!
/*mehrzeiliges Makro*/
#define MAX(a,b) (a>b?\
b: \
a)
//Dies ist ein Zeilenkommentar \
welcher in dieser Zeile fortgesetzt wird
/\
* dies ist ein Blockkommentar*\
/
//hinter der Zeilenfortsetzung darf nur ein CR/LF folgen
#define MAX2(a,b) \ //so dass hier kein Kommentar folgen darf
a>b?a:b
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Innerhalb von Char-Literatoren und Strings wird '\' als Escape-Operator genutzt, welche das '\' und ein oder mehrere folgende Zeichen ersetzt (siehe Kap.[[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Grundlagen:Literale/Konstanten]]). Daher darf hinter Backslash als Zeilenfortsetzungszeichen kein weiteres Zeichen folgen.
== Gültigkeit/Sichtbarkeit von Variablen ==
Vorrangig in der objektorientierten Programmierung werden mit Namensräumen Objekte und deren Methoden/Attribute in einer Art Baumstruktur strukturiert. Dies ermöglicht eine eindeutige Ansprache von Variablen/Objekte, aber auch eine doppelte Verwendung von Methoden-/Attributnamen in unterschiedlichen Namensräumen. Ergänzend zu den Namensräumen kann mit public/private/proteced eine Zugriffsbeschränkung von Methoden/Attributen definiert werden.
Die Programmiersprache C unterstützt keinen Namensraum. Zugriffsmodifikatoren werden indirekt über Header-Dateien getätigt. Hinsichtlich der Gültigkeit/Sichtbarkeit unterscheidet C folgende Bereiche [C11 6.2.1]:
* Funktionen (Function Scope)
* Datei (File Scope)
* Block (Block Scope)
* Funktionsparameter in Prototypen (Function Prototype Scope)
Innerhalb eines Gültigkeitsbereiches dürfen Variablen-/Funktions-/Datentypnamen nicht doppelt genutzt werden.<br />
In der Programmiersprache C++ sind weitere Scope wie z.B. Class Scope, Enumationation Scope und ergänzend das Konzept von Namensräumen vorhanden (Beschreibung folgt).
=== Funktionsweite Sichtbarkeit ===
Eine Label-Definition (als Sprungmarke für die goto-Anweisungen) erfolgt immer mit funktionsweiter Sichtbarkeit/Gültigkeit. Die genaue Beschreibung dieses Sichtbarkeitstyps erfolgt im Rahmen des Kapitels [[Programmieren in C/C++: Grundlagen #Label + Goto|Grundlagen:Label+Goto]].
=== Dateiweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp-Definition außerhalb eines Block-Scopes oder von Funktionsparameter, so sind diese innerhalb der gesamten Datei und bei Funktionen/Variablen ergänzend Projektweit (für alle Objektdateien) sichtbar/gültig (= global) (In der C-Spec unter dem Stichwort 'Linkage' beschrieben, siehe Kapitel [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage| DatentypeSpecifier:Internal/External Linkage]]). Alle globalen Funktionen/Variablen können von allen Dateien aus genutzt/zugegriffen werden (sofern sie zuvor deklariert wurden).<br />
Beispiel:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Deklaration von global,
//welche in Datei1.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Deklaration von func(),
//welche in Datei2.c definiert wird
extern void func(void);
//Definition der Variablen global
int global=0;
int main(void) {
func();
global++;
printf("global=%d\n",global);
return 0;
} | datei2_c=#include <stdio.h>
//Deklaration von global,
//welche in example.c definiert wird
extern int global;
//Definition der Funktion func()
void func(void) {
global++;
printf("func() called\n");
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird das Schlüsselwort 'static' der Variablen/Funktionsdefinition vorangestellt, so wird die Sichtbarkeit/Gültigkeit auf Dateiweit eingeschränkt. Variablen/Funktionen können nur innerhalb der (Objekt-) Datei genutzt werden und sind für anderen (Objekt-)Dateien unsichtbar. (Siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Internal/External Linkage|DatentypeSpecifier:Internal/External Linkage]] Internal/External Linkage)
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
return 0;
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
int main(void) {
var1++;
printf("example.c:var1=%d\n",var1);
void func(void); //Prototyp für func()
func();
return 0;
} | datei2_c=#include <stdio.h>
//Dateiweite Sichtbarkeit von var1
static int var1;
void func(void) {
static int var2; //Vorsicht, static
// hat hier eine andere Bedeutung
var1++;
printf("datei2.c:var1=%d\n",var1);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Projektweite Gültigkeit bedeutet insbesondere, dass keine doppelten Benennung von Variablen/Funktionen/Datentypen innerhalb des gesamten Projektes erlaubt sind, d.h. alle Variablen/Funktionennamen über alle Dateien/Librarys eindeutig sein müssen.<br>
Beispiel 1:
{| class="wikitable"
|-
! Datei1.c !! Datei.2
|-
| <syntaxhighlight lang="C">
#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
}</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int a=1;
int main(int argc,char *argv[])
{
printf("Hello World %d",a);
void dummy(void); //Deklaration von Dummy
dummy();
return 0;
} | datei2_c=#include <stdio.h>
#include <stdio.h>
int a=7;
void dummy(void)
{
printf("Hello Again %d\n",a);
} | execCompilerOptions=datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der Linker meldet beim Zusammenfügen der Objekt-Dateien, dass die Variable a bereits woanders definiert sei (multiple definition of `a';)!
Beispiel 2:
<syntaxhighlight lang="C">
#include <stdio.h> //fuer printf() size_t stderr
int printf=7;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int printf=7;
int main(int argc,char *argv[])
{
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hier meldet der Compiler eine Fehlermeldung, da das Symbol printf zu einen als Variable und zum anderen als Funktion (innerhalb der inkludierten Datei stdio.h beschrieben) genutzt wird ('printf' redeclared as different kind of symbol).
=== Blockweite Sichtbarkeit ===
Erfolgt eine Funktion-/Variablen-/Datentyp Definition innerhalb einer Funktion, als Funktionsparameter oder eines Blockes, so sind diese nur innerhalb des Blockes sichtbar/gültig (=Lokale Variable). Blöcke können verschachtelt sein, so dass das bei identischer Namensgebung innere Definitionen Vorrang haben. Ebenso haben Blockdefinitionen Vorrang vor Datei-/Projektdefinitionen (überdecken diese):
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(void) {
int var2; //var2 ist nur innerhalb
//von main() sichtbar
struct xyz //Datentyp ist nur innerhalb
{int x,y,z;};//von main()
//sichtbar/gültig
extern void func(void); //Deklaration
//ist nur innerhalb von
//main() sichtbar/gültig
func();
}
void foo(void) {
struct xyz var_xyz; //Fehler, da
//Datentypedefinition hier nicht mehr
//gültig ist!
func(); //Fehler, da Deklaration
//hier nicht mehr gültig ist
} | datei2_c=#include <stdio.h>
void func(void) {
int var2=1; //var2 ist
//nur innerhalb von
//func() sichtbar
{
int var2=2;
//var2 ist nur innerhalb
//dieses Blockes sichtbar
printf("%d\n",var2);
}
printf("%d\n",var2);
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sichtbarkeit von Funktionsparameter in Protypen ===
Soll eine Funktion aufgerufen werden, die zuvor nicht definiert wurde, so ist ein Prototyp/(Forward)deklaration der Funktion notwendig (siehe nachfolgendes Kapitel). Die Parameterliste dieses Prototyps hat seinen eigenen Gültigkeitsbereich.<br/>
Beispiel:
<syntaxhighlight lang="C">
int a; //a im File Scope
int func(int a, int b); //a und b im Function Prototyp scope
</syntaxhighlight>
Hinweis:
* Bei Prototypen ist die Angabe von Variablenname nicht notwendig. Die alleinige Angabe des Datentyps ist ausreichend
=== Zuordnung der Gültigkeitsbereiche zu globalen/lokalen Variablen ===
Zum einfacheren Verständnis wird im Skript von folgenden Begrifflichkeiten gesprochen:
* '''Globale''' Variablen-/Funktionen-/Datentypdefinitionen → Projektweite Sichtbarkeit/Gültigkeit
* '''Statisch globale''' Variable/Funktionen → Dateiweite Sichtbarkeit/Gültigkeit
* '''Lokale''' Variablen/Funktionen/Funktionsparameter/Datentypen → Nur innerhalb des zugehörigen Blockes sichtbare/gültig
* '''Statisch lokale''' Variablen → Nur innerhalb der Funktion sichtbar/gültig, mit der Besonderheit, dass die Gültigkeit über der Laufzeit der Funktion gilt (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Static Storage Class Specifier|DatentypeSpecifier:Static Storage Class Specifier]])
=== Speicherzuweisung ===
Für die einzelnen Gültigkeitsbereiche werden im Speicher (und auch in der Objekt-Datei) unterschiedliche Speicherbereiche (Segmente) vorgehalten, d.h. der Compiler teilt den Speicher in unterschiedliche Bereiche auf und weist den Variablen/Funktionen in Abhängigkeit der Gültigkeit/Sichtbarkeit unterschiedliche Speicherbereiche zu!
[[File:Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten).png|thumb|Zuordnung von Inhalten eines C-Programms zu Speicherbereichen (Segmenten)]]
Zur Ermöglichung von Rekursion werden lokale Variable auf dem Stack gehandelt. Mit Aufruf einer Funktion oder öffnen eines neuen Block-Scopes wird Speicher auf dem Stack reserviert, der bei Beenden des Scopes wieder freigegeben wird. Die Speicheradresse von lokalen Variablen ist somit nicht Fix, sondern hängt von der Aufrufhierarchie ab!
Globale und statisch globale Variablen werden nicht auf dem Stack gehalten, sondern bekommen einen 'festen' Speicherbereich (hier DATA/BSS/RODATA) während der gesamten Laufzeit des Programms zugewiesen. Die Adresse dieser Variablen sind somit konstant. Das genutzte Speichersegment von globalen Variablen hängen von der Art der Variablen ab. Initialisierte Variablen werden im DATA-Segment gesammelt, welcher mit dem Initialisierungswert der Variablen initialisiert wird. Nicht initialisierte globale Variablen landen im BSS-Segment, so dass diese mit Programmstart durch Füllen dieses Blockes mit 0 auf 0 gesetzt werden.
Konstante globale Variablen werden im RODATA-Segment gehalten. Über das Betriebssystem kann dieser Speicherbereich auf nur Lesbar gesetzt werden.
Dynamische Speicheranforderungen, resp. Speicher, dessen Gültigkeit über die Laufzeit einer Funktion hinausgeht, wird im Heap gesammelt. Für die Verwaltung dieses Speichers ist der Programmierer zuständig.
Entsprechend globalen Variablen wird für Funktionen ebenfalls ein eigener Speicherbereich (TEXT Segment) vorgesehen. Im Gegensatz zu Variablen, wo im Speicher der dazugehörige Inhalt gespeichert ist, ist der Speicherinhalt von Funktionen die Maschinenanweisungen. Die Speicheradresse der Funktionen sind konstant.
Hinweis:
* Die Speicheradresse von sowohl globalen und statisch globalen Variablen als auch von Funktionen ist konstant und ändert sich während der Laufzeit des Programms nicht. Die Adressvergabe dieser Variablen und Funktionen erfolgt somit nicht zur Laufzeit sondern durch die Toolchain (hier der Linker).
* Dieses Konzept ist allgemeingültig, gilt nicht nur für die Programmiersprache C/C++
== Definition/Deklaration(Prototyp) ==
Der C-Compiler ist ein Single-Pass Compiler (siehe Kap [[Programmieren in C/C++: Einführung/Literatur#Arbeitsweise eines Compilers | Einführung/Literatur:Arbeitsweise eines Compilers ]]), d.h. für den Übersetzungsvorgang wird der Quellcode einmalig eingelesen und von vorne nach hinten abgearbeitet. Dies bedingt, dass keine Vorwärtsbezüge im Quelltext enthalten sein dürfen:
* keine Variable genutzt werden kann, die erst später definiert wird (da der Compiler in Abhängigkeit des Datentyps (den er dann noch nicht kennt) keine entsprechende Maschinensprachebefehle erzeugen kann)
* keine Funktion aufgerufen werden kann, die erst später definiert wird (da der Compiler nicht weiß, welcher Datentyp die Übergabewerte haben und folglich keine Maschinensprachebefehle zur Konvertierung und Übergabe der Variablen erzeugen kann)
* kein Datentyp genutzt werden kann (struct, union, enum, typedef), welcher erst später definiert wird (da der Compiler nicht weiß, wieviel Speicher er für die Variable reservieren muss)
Eine Lösungsvariante dieser Problematik ist, im Quellcode alle Variablen/Funktionen/Datentypen/Makros zu definieren, bevor diese erstmalig genutzt werden (Funktion main() steht dann folglich am Ende des Quellcodes):
<syntaxhighlight lang="C">
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
//Hier kein Zugriff auf var möglich!
//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(void) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) { //foo() wird vor dem ersten Aufruf definiert
var++; //Hier kein Zugriff auf var möglich!
uchar xyz;//Hier kein Zugriff auf Datentyp uchar möglich!
}
int var; //var wird vor dem ersten Aufruf definiert
typedef unsigned char uchar; //Definition des Datentyps uchar
int main(int argc, char *argv[]) {
foo(); //da zuvor definiert kann diese Funktion hier aufgerufen werden
var++; //dito
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Sollen globale Funktionen/Variablen in Datei1.c genutzt werden, die in Datei2.c definiert sind, so schlägt diese Vorgehensweise fehl. Um auch dieses zu ermöglichen, bietet C die Möglichkeiten von Prototypen/Deklarationen an. Diese teilt dem Compiler mit, wie im späteren Ablauf die Variable, die Funktion definiert wird, bzw. dass es diesen Datentyp geben wird:
{| class="wikitable"
|-
! Datei1.c !! Datei2.c
|-
| <syntaxhighlight lang="C">
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
}
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Prototyp für Variable var
extern int var;
//Prototyp für Funktion foo
void foo(void);
int main(int argc, char *argv[]) {
foo(); //Compiler kann aufgrund
var++; //der Prototypen diese
//Aufruf in Maschinen-
//sprachebefehle umsetzen
} | datei2_c=#include <stdio.h>
//Definition der Variablen var
int var;
//Definition der Funktion foo
void foo(void) {
} | execCompilerOptions=-Wall datei2.c|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Innerhalb der C-Spezifikation werden für den Umgang mit dieser Problematik die Begriffe 'Declaration' und 'Definition' genutzt. Da diese Begriffe jedoch nicht klar abgegrenzt werden und auch für viele weitere Aspekte genutzt werden, sollen in diesem Skript in Anlehnung an den Wikipedia Artikel {{w|Deklaration (Programmierung)|Deklaration (Programmierung)}} (im Absatz zur Programmiersprache C/C++) die Begriffe Definition/Deklaration wie folgt genutzt werden:
;Definition: entspricht der Belegung/Reservierung von Speicherplatz
:* Bei der Definition einer Variablen wird hiermit Speicherplatz entsprechend dem Datentyp der Variable belegt:
:<syntaxhighlight lang="C">
int var1; //entsprechend der Größe des Datentyps int wird
//Speicherplatz für die Variable var1 reserviert
int var2=4711; //Dito, ergänzend wird dieser Speicherplatz mit dem
//Wert 4711 initialisiert
</syntaxhighlight>
:* Bei einer Funktion wird Speicherplatz zur Aufnahme der Maschinenbefehle belegt:
:<syntaxhighlight lang="C">
void foo(void) { //Die Anweisungen in den geschweiften Klammern
//werden in Maschinenbefehle übersetzt. D.h. die
//Funktion foo() belegt Speicher, dessen Inhalt
//die Maschinensprachebefehle sind
}
</syntaxhighlight>
:* Ergänzend wird der Begriff Definition auch in Verbindung mit der Definition von neuen Datentypen genutzt!
;Deklaration/Prototyp: ist die Mitteilung an den Compiler, wie diese Variable/Funktion an einer späteren Stelle im Source-Code oder in einer anderen Source-Datei definiert wird. Auf Grundlage dieser 'vorab' Information kann der Compiler die passenden Maschinensprachebefehle für den Zugriff/Aufruf auf die Variablen/Funktion einsetzen:
:<syntaxhighlight lang="C">
extern int var1; //Deklaration von var1
extern void foo(void); //Deklaration von foo()
void foo(void); //Deklaration von foo()
</syntaxhighlight><br />
Insbesondere bei dem Umgang mit der Deklaration gilt es Folgendes zu berücksichtigen:
* Deklarationen werden entweder:
:* am Anfang einer C-Datei geschrieben, so dass Funktionen/Variablen im Zugriff stehen, die erst später in der C-Datei definiert werden (entspricht dann der Private Anweisung in anderen Sprachen)
:* in Header-Dateien geschrieben, so dass diese Variable/Funktionen für alle sichtbar sind, welche diese Header-Datei einbinden (entspricht der Public Anweisung in anderen Sprachen)
* Deklarationen von Funktionen werden in der C-Spec als (function) Prototyp bezeichnet und sind dadurch gekennzeichnet, dass diese mit einem Semikolon abgeschlossen sind. Der Specifier 'extern' ist hier optional und sagt eigentlich aus, dass diese Funktion external Linkage besitzt (siehe [[Programmieren in C/C++:_DatentypeSpecifier#Internal/External Linkage | DatentypeSpecifier:Internal/External Linkage]]). Die Benennung der Parametervariablen sind gleichermaßen optional:
:<syntaxhighlight lang="C">
extern int foo(int var1, float var2); //Deklaration
extern int foo(int , float ); //Deklaration
int foo(int var1, float var2); //Deklaration + external Linkage
int foo(int , float ); //Deklaration + external Linkage
</syntaxhighlight>
* Für globale Variablen gibt es keine (Variablen) Prototype. Stattdessen muss zur Bekanntgabe des Datentyps der Specifier 'extern' vorangestellt werden, mit welchen ergänzend zum Ausdruck gebracht wird, das diese Variable external Linkage und damit globale Gültigkeit hat (siehe Kap [[Programmieren in C/C++: DatentypeSpecifier# Extern - Storage Class Specifier| DatentypeSpecifier:Extern - Storage Class Specifier]]). Da die Deklaration einzig zur Bestimmung der Zugriffsmethoden auf Maschinenspracheebene genutzt wird, können diese keine Initialisierungswerte enthalten:
:<syntaxhighlight lang="C">
extern int var1;
extern int var2=7; //KO Deklarationen können keine
//Initialisierungswerte haben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern int foo;
extern int foo=7;
int main(int argc, char *argv[]) {
return foo;
}
int foo=7;| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen von statisch globalen, lokalen und statisch lokalen Variablen nicht möglich sind:
:<syntaxhighlight lang="C">
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sich auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
extern static int glob; //keine Deklaration von statisch globalen
//Variablen möglich
int main(int argc, char *argv[]) {
extern int var; //Deklaration bezieht sicht auf eine globale
//Variable, die nicht definiert ist
extern static int lok;
printf("%d %d\n",var,lok);
int var;
static int lok;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklarationen für identische Variablen/Funktionen können beliebig oft erfolgen, sofern der Datentyp identisch ist:
:<syntaxhighlight lang="C">
extern int var;
extern int var; //OK, doppelt Deklaration mit identischen Datentyp
extern unsigned int var; //KO, Doppelte Deklaration mit unterschiedlichen
// Datentyp
</syntaxhighlight>
* Sofern eine Deklaration und eine Definition in der identischen Datei erfolgen überprüft der Compiler, ob Deklaration und Definition identisch sind. Es empfiehlt sich, die eigene Header-Datei (in welcher die Deklaration normalerweise enthalten ist) zu inkludieren:
:{| class="wikitable"
|-
! Datei1.c !! Datei1.h
|-
| <syntaxhighlight lang="C">
//Include der eigenen Header-Datei
#include "datei1.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
</syntaxhighlight> ||
<syntaxhighlight lang="C">
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
</syntaxhighlight>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Include der eigenen Header-Datei
#include "example.h"
int var1; //Definition von var1
short var2; //Definition von var2
int var3; //Private Variable
//da kein Prototyp
//im Header vorhanden
void func(void) {
}
int main(int argc, char *argv[]) {
return 0;
} | example_h=
extern int var1; //Deklaration
extern char var2; //KO, da Deklaration
//von Definition
//abweicht
void func(int); //KO, da Deklaration
//von Definition
//abweicht
| execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Datei kann eine Variable identischen Datentyps mehrmals definiert werden (bei identischen Initialisierungswert). Diese Definitionen werden vom Compiler als eine Definition angesehen. Wenn jedoch eine identische Variable in unterschiedlichen Dateien definiert wird, so legt jede Datei eine eigene unabhängige Variable an, welche dann beim Zusammenführen der Objektdateien durch den Linker zu Fehler führt. Da Header-Datei zumeist in mehrere C-Dateien inkludiert werden, sind Definitionen in Header-Dateien 'verboten'.
* Deklarationen innerhalb eines Block-Scopes oder eines Function Prototyp Scopes sind nur in diesen Bereich gültig.
== Grundlegende Datentypen und Typsicherheit ==
Die Programmiersprache C kennt folgende grundlegende Datentypen (siehe Kap. [[Programmieren in C/C++: Datentypen | Datentypen]]). Von jedem Datentyp kann ein Zeiger angelegt werden:
{| class="wikitable"
|-
! Datentyp !! Bsp. für Datentyp !! Bsp. für Zeiger auf Datentyp
|-
| Ganzzahl ||
<syntaxhighlight lang="C">
char var;
int var;
short int var;
long int var;
long long int var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
char *ptr;
int *ptr;
short int *ptr;
long int *ptr;
long long int *ptr;
</syntaxhighlight>
|-
| Gleitkommazahl ||
<syntaxhighlight lang="C">
double var;
float var;
long double var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
double *ptr;
float *ptr;
long double *ptr;
</syntaxhighlight>
|-
| Funktionen ||
<syntaxhighlight lang="C">
void func(void) {}
</syntaxhighlight>
|| <syntaxhighlight lang="C">
void (*pfunc)(void);
</syntaxhighlight>
|-
| Arrays ||
<syntaxhighlight lang="C">
int arr[10];
float arr[3][3];
</syntaxhighlight>
||
<syntaxhighlight lang="C">
int (*parr);
float (*parr)[3];
void (*pfunc[5])(void);
</syntaxhighlight>
|-
| Strukturen/Unions ||
<syntaxhighlight lang="C">
struct xyz {int x,y,z};
union abc {int a,b,c};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
struct xyz *ptr;
union abc *ptr;
</syntaxhighlight>
|-
| Aufzählungstyp ||
<syntaxhighlight lang="C">
enum abc {A,B,C};
</syntaxhighlight>
||
<syntaxhighlight lang="C">
enum abc *ptr;
</syntaxhighlight>
|-
| Boolescher Datentyp ||
<syntaxhighlight lang="C">
_Bool var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Bool *ptr;
</syntaxhighlight>
|-
| Komplexe Zahlen ||
<syntaxhighlight lang="C">
_Complex var;
</syntaxhighlight>
||
<syntaxhighlight lang="C">
_Complex *ptr;
</syntaxhighlight>
|}
C/C++ unterscheidet zwischen vorzeichenbehafteten <code>signed</code> und vorzeichenlosen <code>unsigned</code> ganzzahligen Datentypen. Vorzeichenlose Datentypen können nur positive Zahlen incl. der 0 aufnehmen (Anwendungsbereich bspw. Speicheradressen/Arrayindexe, welche nicht negativ sein können). Deren max. Zahlenwert ergibt sich aus der Datenbreite N des Datentyps 2<sup>N</sup>-1. Ein Vergleich eines vorzeichenlosen Datentyps mit ≥ 0 ist somit immer TRUE:
<syntaxhighlight lang="C">
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt"); //dieser ggf. vom Compiler wegoptimiert wird!
for(var=10; var>=0; var--); //Endlosschleife! 0 dekrementiert ergibt 255
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char var=0;
if(var >= 0) //Bedingung ist immer erfüllt, so dass
printf("Bedingung erfüllt\n"); //dieser ggf. vom Compiler wegoptimiert wird!
//Beim Öfffnen des Compiler-Fensters ist die IF-Anweisung nicht farblich
//hervorgehoben. Dies bedeutet, dass diese Zeile wegoptimiert wurde und folglich
//kein Maschinencode für diese Anweisung erzeugt wurde
for(var=10; var>=0; var--) //Endlosschleife! 0 dekrementiert ergibt 255
printf("%u ",var),fflush(stdout);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Vorzeichenlose Datentypen halbieren den verfügbaren Zahlenbereich und 'weisen' dem oberen Wertebereich den negativen Zahlen zu.<br>
Wird ein ganzzahliger Datentyp ohne Angabe des Vorzeichentyps (signedness) definiert, so ist diese vorzeichenbehaftet. Bei vorzeichenlosen Variablen muss explizit <code>unsigned</code> vorangestellt werden. Die Voranstellung von <code>signed</code> ist optional. Einzige Ausnahme stellt der Datentyp char dar. Hier gibt die Spezifikation keine default signedness vor, so dass bei Nutzung dieses Datentyps zur Aufnahme von Zahlen immer signed oder unsigned vorangestellt werden sollte!<br>
Innerhalb des Formatstrings bei den printf()/scanf() Anweisungen '''muss''' die signedness vom Programmierer händisch berücksichtigt werden. Die Formatanweisung %d und %i interpretieren die übergebenen Zahl als vorzeichenbehaftete Zahl. Soll eine vorzeichenlose Zahl ausgegeben werden, so muss %u verwendet werden:
<syntaxhighlight lang="C">
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%d varu=%u",vari,varu); //Korrekt
printf("vari=%u varu=%i",vari,varu); //Falsche Werteausgaben!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
signed int vari=-10;
unsigned int varu=3000000000;
printf("vari=%12d varu=%12u\n",vari,varu); //Korrekt
printf("vari=%12u varu=%12i\n",vari,varu); //Falsche Werteausgaben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit der Definition (dem Anlegen) einer Variablen eines Datentyps wird Speicher entsprechend der Größe des Datentyps reserviert. Optional kann dieser Speicher initialisiert werden. Über den Datentyp wird ausgesagt, wie der Inhalt des Speichers zu interpretieren ist:
<syntaxhighlight lang="C">
char var1; //Speicherplatzreservierung von 1 Byte
//Inhalt der Speicherstelle wird als Zahl interpretiert
//(Hinweis: ASCII-Zeichen sind Zahlen)
double var2=47.11; //Speicherplatzreservierung von 8 Byte
//Inhalt der Speicherstellen wird als Gleitkommazahl
//interpretiert (bestehend aus je einer Ganzzahl für
//Mantisse und Exponent)
short arr[10]; //Speicherplatzreservierung von 10*2 Byte
//Inhalt der 10 Speicherstellen werden als Ganzzahl
//interpretiert
</syntaxhighlight>
Die Funktionalität der Operatoren hängt vom Datentyp der Operanden ab. Der Plus-Operator angewendet auf ganzzahlige Operanden führt eine Ganzzahl Addition aus, angewendet auf gleitkomma Operanden eine Gleitkomma Addition. Ist einer der Operanden ein Zeiger, so wird eine Zeigeraddition angewendet. Für andere Datentypen ist der Plus-Operator nicht definiert, so dass der Compiler einen Fehler wirft. '''Bei der Betrachtung eines Ausdruckes sollte dem genutzten Datentypen folglich eine besondere Aufmerksamkeit zuteil werden''':
<syntaxhighlight lang="C">
int vari=47;
vari+12; //(int) + (int) → Ganzzahladdition
float varf=12.3;
3.1415F+varf; //(float) + (float) → Gleitkommaaddition
int *ptr=&vari;
ptr+3; //(int *) + (int) → Zeigeraddition
int arr[3];
arr+3; //(int (*)) + (int) → Zeigeraddition
</syntaxhighlight>
Das Ergebnis einer Operation hat ebenfalls einen Datentyp. Eine Ganzzahl Addition gibt bspw. als Ergebnis einen Ganzahl Datentyp zurück, eine Gleitkomma Addtition einen Gleitkomma Datentyp und ein Vergleichsoperator den Datentyp _Bool:
<syntaxhighlight lang="C">
int vari1=47;
int vari2=11;
vari1 + 12 + vari2; //((int)+(int)+(int))→((int)+(int))→(int)
40 < vari1 < 50; //((int)<(int)<(int))→((_Bool=int)<(int))→(_Bool=int)
</syntaxhighlight>
Wie Operatoren haben auch Funktionen Operanden (in Form von Übergabeparameter). Das Ergebnis eines Funktionsaufrufes wird ebenfalls in Form eines Datentyps zurückgegeben:
<syntaxhighlight lang="C">
float add(int par1,par2) {return par1+par2;}
int vari1=47;
int vari2=11;
vari1 + add(var2,12); //(int)+((int),(int)→(float))→(int)+(float)→(float)
</syntaxhighlight>
Wird auf einen Operator gleichermaßen ein vorzeichenbehafteter und ein vorzeichenloser Operand angewendet, so kann es zu unerwarteten Konvertierungsproblemen führen:
<syntaxhighlight lang="C">
unsigned char varu=12;
signed char vars=-12;
float varf;
varf = varu + vars;
if(vars < varu)
</syntaxhighlight>
Sind die Datentypen der Operanden nicht 'kompatibel', so 'passt' der Compiler die Datentypen im Falle von Ganzahl und Gleitkomadatentypen per impliziter Regel an (siehe Kap. [[Programmieren in C/C++: Datentypen#Implizite Typumwandlung | Datentypen:Implizite Typumwandlung]]). Über explizite Typumwandlung (siehe Kap.[[Programmieren in C/C++: Datentypen# Explizite Typumwandlung|Datentypen:Explizite Typumwandlung]]) kann ein Datentyp z.T. in einen anderen Datentyp gewandelt werden.
In allen anderen Fällen ist C Typsicher, d.h. der Compiler gibt zumindest eine Warning aus, wenn die Datentypen nicht identisch sind und der Compiler keine implizite Regel anwenden kann.
Tipp:
* Compiler gibt bei Fehlermeldung oftmals die erwarteten und die vorhandenen Datentyp an. Wenn solch eine Fehlermeldung kommt, sollten sie sich a) überlegen, was wollten sie syntaktisch geschrieben haben und b) was haben sie in der Tat geschrieben. Ein Google nach einer Lösung des Compilerproblems löst zumeist nicht das Problem, sondern umgeht es!
Hinweis:
* Ein guter Programmierer sollte die Datentypen so wählen, dass:
:* die Datentypen zum Inhalt und zum Wertebereiches passen
:* keine Datentypkonvertierungen notwendig sind
: andernfalls besteht die Gefahr, dass hiermit Laufzeitfehler einprogrammiert werden.
* Wenn Datentypkonvertierungen notwendig sind, sollte die explizite Konvertierung genutzt werden
== Abhängigkeiten bzgl. Rechnerarchitektur ==
Kenngrößen von Prozessoren sind unter anderem die Anzahl der Bits für den Datentransport und für Arithmetisch-/Logische-Operationen (→ Datenbreite) und die Anzahl der Bits für die Adressierung des Speichers (→ Adressierungsbreite). Die Datenbreite sagt dabei aus, welche max. Datenbreite ein Maschinenbefehl (zumeist in einem Taktzyklus) transportieren/berechnen kann. Werden programmtechnisch größere Datenbreiten benötigt, bedingt dies, dass hierzu mehrere Maschinenbefehle notwendig sind. Wenn kleinere Datenbreiten notwendig sind, so wird oftmals das Ergebnis abgeschnitten (sofern der Prozessor keine Befehle für den Umgang mit kleineren Datentyp beherrscht):
{| class="wikitable"
|-
! 32-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 64-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
! 16-Bit Datentransport/Operation<br /> bei 32-Bit Datenbreite
|-
| <syntaxhighlight lang="C">
int32_t a32,b32;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int64_t a64,b64;
</syntaxhighlight>
|| <syntaxhighlight lang="C">
int16_t a16,b16;
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=b32;
mov eax,b32
mov a32,eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=b64;
mov eax ,b64
mov edx ,b64+4
mov a64 ,eax
mov a64+4,edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
//a16=b16;
movz eax,b16
mov a16,ax
</syntaxhighlight>
|-
| <syntaxhighlight lang="asm">
// a32=a32+b32;
mov edx, a32
mov eax, b32
add eax, edx
mov a32, eax
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a64=a64+b64;
mov ecx , a64
mov ebx , a64+4
mov eax , b64
mov edx , b64+4
add eax , ecx
adc edx , ebx
mov a64 , eax
mov a64+4, edx
</syntaxhighlight>
|| <syntaxhighlight lang="asm">
// a16=16+b16;
movzx eax, a16
mov edx, eax
movzx eax, b16
add eax, edx
mov a16, ax
</syntaxhighlight>
|}
Die Adressierungsbreite gibt an, mit welcher Bitbreite der Speicher adressiert werden kann:
* Bei einem 32-Bit System können 2<sup>32</sup>=4.294.967.295=4Gi Bytes/Speicherstellen adressiert werden
* Bei einem 16-Bit System können 2<sup>16</sup>=65.536=64Ki Bytes/Speicherstellen adressiert werden
* Bei einem 64-Bit System können 2<sup>64</sup>=18.446.744.073.709.551.616 =16Ei ~18Exa Bytes/Speicherstellen adressiert werden
Waren die Datenbreite und die Adressierungsbreite bei den ersten Prozessoren noch unterschiedlich, so sind diese heutzutage zumeist identisch. Bei einem 32-Bit Prozessor bedeutet dies, dass dieser max. 4Gi Bytes Speicherstellenstellen adressieren kann und Maschinenbefehle für den Datentransport und die Berechnung von 32-Bit Datenworten beinhaltet.
Die Datenbreite und auch die Adressierungsbereite haben direkten Einfluss auf die Programmiersprache:
* Wird defaultmäßig mit größerer Datenbreite gerechnet, als der Prozessor 'von Hause' aus unterstützt, so werden die erzeugten Maschinenprogramme größer und langsamer (Umgedreht bedeutet dies jedoch nicht, dass die Maschinenprogramme kleiner und schneller werden)
* Die max. Größe von Verbunddatentypen und Arrays ergibt sich aus der Adressierungsbreite des Prozessors
Die Intention der Programmiersprache C/C++ ist, die Prozessorarchitektur optimal zu nutzen. Dementsprechend sind diverse Eigenschaften der Sprache nicht fest spezifiziert, sondern von der Rechnerarchitektur abhängig.
=== Integer Datentyp ===
Intention von C/C++ ist, dass der Umgang mit dem Grunddatentyp 'int' möglichst direkt in einen Maschinensprachebefehl umgesetzt werden kann.<br />
Bei einem 16-Bit Prozessor hat der Datentyp int daher eine Breite von 16-Bit und bei einem 32-Bit Prozessor eine Breite von 32-Bit (siehe Kap [[Programmieren in C/C++: Datentypen # Ganzzahlige Datentypen|Datentypen:Ganzahl Datentypen]]). Über vorangestellte Qualifier kann dieser Grunddatentyp verkleinert/vergrößert werden.
=== Integer Arithmetik ===
Ganzzahlen haben nur einen begrenzten Wertebereich. Wird dieser bspw. durch eine Addition überschritten (d.h. das Rechenergebnis benötigt zur Darstellung mehr Stellen, als der Datentyp 'hergibt'), so gibt es zwei Vorgehensweisen:
* Arithmetischer Überlauf (siehe {{w|arithmetischer Überlauf}}): Die nicht speicherfähigen Stellen werden verworfen, so dass i.d.R. ein falsches Ergebnis erzeugt wird!
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist (254+3)%256=1
c=a*b; //c ist (254*3)%256=250
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
unsigned char a=254,b=3,c1,c2;
c1=a+b; //c ist (254+3)%256=1
c2=a*b; //c ist (254*3)%256=250
printf("c1=%hhu c2=%hhu\n",c1,c2);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sättigungsarithmetik (siehe {{w|Sättigungsarithmetik}}): Alle Operationen laufen innerhalb eines festen Intervalls ab, so dass Überläufe und Unterläufe auf dieses Intervall begrenzt werden:
:Beispiel:
:<syntaxhighlight lang="C">
unsigned char a=254,b=3,c;
c=a+b; //c ist MAX((254+3),255)=255
c=a*b; //c ist MAX((254*3),255)=255
</syntaxhighlight>
Die Spezifikation von C macht bezüglich der zu nutzenden Methodik keine Vorgaben, so dass das Handling von der ALU des Prozessors abhängt. Aus Komplexitäts- und Geschwindigkeitsgründen ist dies zumeist der arithmetische Überlauf. Nur bei Spezialprozessoren (z.B. DSP Digital Signal Processor) kommt z.T. die Sättigungsarithmetik zum Einsatz.
=== Gleitkomma Datentyp und Arithmetik ===
Für den Umgang mit Gleitkommazahlen bieten einige Prozessoren spezielle Recheneinheiten ({{w|Gleitkommaeinheit}} Floating Point Units FPU) an. Sowohl die Darstellung von Gleitkommazahlen als auch das Verhalten bei Überlauf/Unterlauf ist damit Herstellerabhängig. Um auch diese Einheiten effektiv nutzen zu können, ist die C/C++ Spezifikation in diesem Bereich ebenfalls sehr offen.
=== Max. Speicherbedarf von Variablen ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C/C++ von der zugrundeliegenden Rechnerarchitektur abhängig:
<syntaxhighlight lang="C">
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
//Zur Darstellung bitte Compiler-Fenster öffnen
//und dort den CC65-Compiler für den 6502 Prozessor auswählen
char a[100000]; //Speicherbedarf=100.000*1Byte=100.000 Bytes
//Bei 16-Bit Architektur KO
//Ab 32-Bit Architektur OK
struct size_16 {
char a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_256 {
struct size_16 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_4096 {
struct size_256 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 {
struct size_4096 a,b,c,d,e,f,g,h,
i,j,k,l,m,n,o,p;
};
struct size_65536 var65536; //Speicherbedarf=65536 Bytes
//Bei 16-Architektur KO
//Ab 32-Architektur OK
int main(int argc,char *argv[]) {
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Im Falle von globalen Variablen erzeugt der Compiler/Linker eine Fehlermeldung. Werden von diesen Datentypen Variablen als lokale Variablen angelegt, so erzeugt dies zur Laufzeit einen Stackoverflow.
=== Zeigervariable ===
Eine Zeigervariable ist eine Variable, die eine Speicheradresse speichert. Die Größe dieses Datentyps hängt von der Adressierungsbreite des Prozessors ab. Unabhängig von dem Datentyp, auf den die Zeigervariable zeigt, ergibt sich folgende Breite:
* 4-Byte bei einer 32-Bit Rechnerarchitektur
* 8-Byte bei einer 64-Bit Rechnerarchitektur
* 2-Byte bei einer 16-Bit Rechnerarchitektur
=== Datentyp size_t ===
Die maximale Größe von Arrays/Strukturen/Unions ist in C von der zugrundeliegenden Rechnerarchitektur abhängig. Sie ergibt sich aus der Adressierungsbreite. Da die Datenbreite des Datentyps int zumeist kleiner als die Adressierungsbreite ist, existiert in C/C++ der vorzeichenlose Datentyp size_t.<br />
Alle Funktionen, welche den Speicherbedarf übergeben bekommen, bzw. zurückgeben (bspw. strlen(), memcpy(), sizeof()) , nutzen den Datentyp size_t:
<syntaxhighlight lang="C">
//Prototypen
size_t strlen(char *str); //Die max. Stringlänge ist durch den
//adressierbaren Speicher vorgegeben
void *malloc(size_t size);
void *memcpy(void *dest, const void *src, size_t n);
</syntaxhighlight>
Der Datentyp size_t ist in der Header-Datei stddef.h der Standard-C-Library per typedef gesetzt. Im Normalfall muss diese Header-Datei nicht explizit inkludiert werden, da bei Nutzung von z.B. strlen() diese bereits durch die Header-Datei string.h inkludiert wird:
<syntaxhighlight lang="C">
typedef unsigned long long size_t; //Bei einer 64-Bit Rechnerarchitektur
</syntaxhighlight>
Hinweis:
* Der Datentyp size_t ist immer ein vorzeichenloser Datentyp (es gibt keine negativen Speicheradressen).
* Mit dem Datentype ssize_t wird eine vorzeichenbehaftete Variante zur Verfügung gestellt, welche hilfreich ist, wenn Speicheradresse subtrahiert werden sollen.
* Soll der Wert vom Datentyp size_t mittels printf() ausgegeben werden, so ist der 'Length Modifier' z und der 'Conversion Specifier' u zu nutzen:
:<syntaxhighlight lang="C">
size_t var=strlen("String");
printf("%zu",var);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[]) {
size_t var=strlen("String");
printf("%zu",var);
printf("%d",var); //Hier sollte es eine Compiler-Warning geben!
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Boolescher-Datentype/Operatoren ==
Ursprünglich gab es den booleschen Datentyp in der Programmiersprache C nicht. Mit C99 wurde zwar der Datentyp <code>_Bool</code> eingeführt, dies änderte jedoch nicht den Umgang mit Anweisungen und Operatoren, die einen booleschen Datentyp erwarten/zurückgeben!
An allen Stellen, an denen ein boolescher Datentyp erwartet wird (z.B. IF-Abfrage, bei booleschen Operationen) wird der Datentyp Ganzzahl, Gleitkommazahl oder Zeiger erwartet (= Scalar-Type) und ausgewertet. Der hierin gespeicherte Zahlenwert sagt aus, ob diese Zahl als True oder False zu interpretieren ist:
* False, wenn Ganzzahl gleich 0 oder Gleitkommazahl gleich 0.0 oder Zeiger gleich NULL
* True, wenn Ganzzahl ungleich 0 oder Gleitkommazahl ungleich 0.0 oder Zeiger ungleich NULL
Beispiel:
<syntaxhighlight lang="C">
int a=3;
double b=0.0;
int *ptr=&a;
while(1);
if(a) {}
for( ; b && ptr ; );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
double b=0.0;
int *ptr=&a;
while(0);
if(a) {}
for( ; b && ptr ; ) {}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Operatoren, welchen einen booleschen Wert zurückliefern (Vergleichs-Operatoren und Boolesche-Operatoren), liefern ein Integer-Datentyp zurück:
* (int)0 für False
* (int)1 für True
Beispiel:
<syntaxhighlight lang="C">
int a=3;
int b= (a==3); //b=1
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3;
int b= (a==3); //b=1
printf("%d",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
In den if()/for()/while() Anweisungen ist folglich kein explizites Konvertieren eines Ganzzahl-/Gleitkomma-/Zeigerwertes mittels des Vergleichs-Operators in einen Booleschen Wert notwendig:
<syntaxhighlight lang="C">
int a;
double b;
if(a) //entspricht if(a!=0)
if(!b) //entspricht if(b==0.0)
while(1) //entspricht while(True)
for(int lauf=1; lauf ; lauf--);
</syntaxhighlight>
Umgedreht kann ein boolescher Wert oder auch das Ergebnis einer booleschen Operation direkt mit einer Ganzzahl- oder Gleitkommazahl verknüpft werden:
<syntaxhighlight lang="C">
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
if( a==1 & b==2)
if(3 < a < 9) //Vorsicht, die Schreibweise lässt ein
//anderes Verhalten erwarten!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
int a=3,b=2;
a=a+1 && 7 << 3 & a==3;
printf("%d\n",a);
if(a==1 & b==2)
printf("true\n");
else
printf("false\n");
if(3 < a < 9)
if( (a==1) & (b==2))
printf("true\n");
else
printf("false\n");
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mit C99 wurde der Datentyp <code>_Bool</code> eingeführt. Dieser entspricht weiterhin einem Integerdatentyp mit der Besonderheit, dass beim Zuweisen eines Wertes dieses auf true oder false geprüft wird und Variablen dieses Datentyps nur die Werte 0 oder 1 annehmen können:
<syntaxhighlight lang="C">
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool! möglich
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
_Bool var1=12;
printf("var1=%d\n",var1); //→ 1
float var2=13.2;
var1=var2;
printf("var1=%d\n",var1); //→ 1
var1--; //Post/Pre Inkrement/Dekrement in C++ nicht auf Datentyp bool!
printf("var1=%s\n",var1?"true(1)":"false(0)"); //→ false
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für den einfacheren Umgang mit dem 'neuen' Datentyp wurde in der Header-Datei <code>stdbool.h</code> die Makros <code>true</code> (als Austauschwert für die Ganzzahl 1) und <code>false</code> (als Austauschwert für die Ganzahl 0) definiert. Ergänzend wird hier der Datentyp <code>bool</code> als Alias auf <code>_Bool</code> gesetzt.
<syntaxhighlight lang="C">
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdbool.h>
bool foo(int par,int min,int max) {
if((par >= min) && (par <= max))
return true;
else
return false;
}
int main(int argc,char *argv[]) {
foo(4,3,6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In C++ gibt es anstatt des Datentypes <code>_Bool</code> den Datentyp <code>bool</code>. Auch sind die beiden Konstanten <code>true</code> und <code>false</code> ohne zusätzliches Einbinden der Header-Datei vorhanden. Der weitere Umgang ist jedoch identisch zu C.
== Literale/Konstanten ==
In Computerprogramm werden an diversen Stellen Konstanten in Source Code genutzt. Sei es als Initialisierungswert für Variablen, als Vergleichswert für Abfragen, zur Definition von Schleifendurchläufe oder als Strings für die Kommunikation. Der Syntax der Programmiersprache bietet dazu verschiedene Möglichkeiten, wie Zahlen zu beschreiben sind und wie der Datentyp vorgeben wird.</br>
Ungeachtet der Schreibweise werden im Computer alle Zahlen identisch als binäre Zalen gespeichert. Beispiele, wie die Zahlen intern gespeichert werden:
<syntaxhighlight lang="C">
int var=17; //0000 0000 0000 0000 0000 0000 0001 0001
short var=0x307;// 0000 0011 0000 0111
char var=017; // 0000 1111
int var=-1; //1111 1111 1111 1111 1111 1111 1111 1111
float var=0.0; //0000 0000 0000 0000 0000 0000 0000 0000
float var=1.0; //0011 1111 1000 0000 0000 0000 0000 0000
</syntaxhighlight>
=== Ganzzahl-Konstanten ===
Im Allgemeinen ordnet der Compiler einer numerischen, ganzzahligen Konstanten den kleinstmöglichen Datentyp beginnend vom Datentyp integer zu. Sobald der Wert der Konstanten den Wertebereich von integer übersteigt, wird der nächst größere passende Datentyp gewählt. Ergänzend gilt, dass alle Ganzzahl-Konstanten als vorzeichenbehaftete Ganzzahl-Konstanten angesehen werden!<br />
Beispiele für integer Konstanten:
<pre>
123
+123
-123 → Formal wird das Minus als Operator angesehen
und die positive Zahl 123 negiert
0x123 → Konstante ist in hexadezimaler Schreibweise notiert
0123 → Konstante ist in oktaler Schreibweise notiert
0b011 → Konstante ist in binärer Schreibweise notiert
nicht offizieller C-Syntax, wird aber von vielen Compiler unterstützt
ab C23-Spezifikation offiziell im C-Syntax enthalten!
6'432'108 → Tausendertrenner (ab C23 und in C++)
6'4'3'2'10 → Tausendertrenner
0x12'23'5 → Tausendertrenner
0b1001'001 → Tausendertrenner
5123123123 → Wertebereich größer als 2^31 so dass automatisch
zum nächst größeren Datentyp konvertiert wird
</pre>
Mit den Suffixen L/l und LL/ll kann der Datentyp long und long long erzwungen werden:
<pre>
12L → Konstante wird in eine long Integer Konstante konvertiert
4711LL → Konstante wird in eine Long Long Konstante konvertiert
</pre>
Mit dem Suffix U/u kann die Konstante explizit auf unsigned gesetzt werden:
<pre>
12U → Konstante wird als vorzeichenlose Zahl gesepeichert
4711ULL → Konstante wird in eine vorzeichenlose
Long Long Konstante konvertiert
</pre>
=== Char-Konstanten ===
In einfachen Anführungsstrichen geschriebene ASCII Zeichen werden entsprechend der {{w|American Standard Code for Information Interchange | ASCII-Tabelle}} als Zahlenwert (Datentyp int) dargestellt:
<pre>
'A' → Integerkonstante 65
'a' → Integerkonstante 97
…
</pre>
Über den {{w|Escape-Sequenz|Escape-Operator}} (Zeichen Backslash '\') wird das/die dem ESCAPE Operator folgende Zeichen gesondert interpretiert. Die im Source-Code erhaltene Zeichenfolge wird im Computerprogramm als ein Zahlenwert (Datentyp int) gespeichert. Dies ist u.A. zur Darstellung von ' und " aber auch zur Darstellung der unteren 32 Zeichen der ASCII Tabelle notwendig (Siehe auch {{w|Steuerzeichen}})
<pre>
ESCAPE Integer- → Bedeutung / (Terminal)funktionalität
Sequence konstante
'\0' = 0 → 0 Character = Stringendezeichen
'\a' = 7 → Bell (erzeugt auf dem Terminal einen Ton)
'\b' = 8 → Backspace (Bewegt den Cursor um eine Position nach links)
'\t' = 9 → Horizontal Tab (Bewegt den Curso auf die nächste horizontale
Tabulatorposition, Abstand ist Terminalspezifisch)
'\n' = 10 → NewLine (Zeilenvorschub)
'\v' = 11 → Vertial Tab
'\r' = 13 → Carriage Return (Wagenrücklauf, Bewegt den Cursor an den
Zeilenanfang)
'\"' = 34 → Double Quote
'\'' = 39 → Single Quote
'\?' = 63 → Question mark
'\\' = 92 → Backslash
'\f' = 12 → FormFeed (Erzeugt auf dem Terminal/Drucker
einen Seitenvorschub)
'\ooo' = 0ooo → Oktal, wobei o Digits von 0..7 sein müssen
'\xdd' = 0xdd → Hexadezimal, wobei d Digits von 0..9 A..F sein müssen
'\udddd' Unicode mit 4 Digits
'\Udddddddd' Unicode mit 8 Digits
</pre>
Beispiel
<syntaxhighlight lang="C">
'A' == 65 == '\101' == '\x41' == '\u0041' == '\U00000041'
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc,char *argv[]) {
//Programmiersprache wurde auf C++ gesetzt
if('A' == 65) printf("'A' == 65\n");
if('A' == '\101') printf("'A' == '\\101'\n");
if('A' == '\x41') printf("'A' == '\\x41'\n");
if('A' == '\u0041') printf("'A' == '\\u0041'\n");
if('A' == '\U00000041') printf("'A' == '\\U00000041'\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true|
lang=c++
}} Öffnen im Compiler Explorer] }}
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
u'b' → unicode 16 (nur C++)
U'b' → unicode 32 (nur C++)
L'b' → wchar_t
</pre>
Hinweis
* Die ASCII-Tabelle basiert auf einer 7-Bit Zeichenkodierung, so dass bspw. die Umlaute 'ä', 'ö' und 'ü' dort nicht kodiert sind. Sollen auch diese Zeichen genutzt werden, so empfiehlt sich der Datentyp wchar_t
=== Gleitkommakonstanten ===
Alle Gleitkommakonstanten sind ohne weitere Angaben vom Datentyp double!
<pre>
555.12
555. → 555.0
.1 → 0.1
4e2 → 400.0
1'234.678'9 → Tausendertrenner (ab C23 und in C++)
0x22.11p13 → Konstante in Hexadezimalen Schreibweise (ab C99)
</pre>
Über Suffixe kann ein alternativer Datentyp erzwungen werden:
<pre>
3.0F → Datentyp float
3.0l → Datentyp long double
</pre>
Hinweis:
* Aufgrund der unterschiedlichen Basis zwischen dem menschlichen Zehner-System und dem computerinternen Binär-System entstehen insbesondere bei den Nachkommastellen Rundungsfehler. Die Konstante 0.1f wird durch die Wandlung intern als 1.00000001490116119384765625e-1 dargestellt (siehe [[Programmieren in C/C++: Datentypen#Gleitkomma Datentypen | Datentypen:Gleitkomma Datentypen]])
* Die C-Spec verlangt, dass die binäre Repräsentation von Gleitkommazahlen zur Laufzeit (z.B. durch die Funktion atof() strtod() scanf("%f")) identisch zur der zur Compilezeit ist. Beispiel:
:<syntaxhighlight lang="C">
if(3.14==atof("3.14")) printf("muss erfüllt sein");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
if(3.14==atof("3.14")) printf("muss erfüllt sein\n");
//3.14 wird vom Compiler in ein Binärwert gewandelt
//Der String "3.14" wird zur Laufzeit mittels atof in ein Binärwert gewandelt
//Beide Wandlungsergebnisse müssen identisch sein
printf("Intern wird 3.14 wie folgt dargestellt %14.20f",3.14);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Konstanten Ausdrücke ===
Ergänzend zu den Zahlenwerten werden auch Ausdrücke durch den Compiler ausgewertet. Als Voraussetzung für die Ausdrücke gilt, dass alle Operatoren Literale/Konstante sein müssen, so dass der Compiler die Berechnung durchführen kann. Als Operatoren können alle im normalem Syntax erlaubten Operatoren (z.B.: +,-,*,/,&,&&,|,||,>>,<<,==,!=) genutzt werden.<br />
Beispiel:
<syntaxhighlight lang="C">
int var1=7*3+5; → wird vom Compiler durch 26 ersetzt
int var2=(4710+(8-1))&-8; → wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); → wird vom Compiler durch 16 * var1 + 154 ersetzt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
int var1=7*3+5; //→ wird vom Compiler durch 26 ersetzt
int var2;
var2=(4710+(8-1))&-8; //→ wird vom Compiler durch 4712 ersetzt
var1=4*4*var1+77*(77%3); //→ wird vom Compiler durch var1 * 16 + 154 ersetzt
return 0;
} | execCompilerOptions=-Wall|
h=g|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Konstante Ausdrücke bieten sich an, um den Sourcecode lesbarer zu gestalten. Da der Compiler die Berechnung durchführt, wird zur Laufzeit keine Rechenleistung benötigt. Einzig die Compiledauer wird etwas erhöht:
<syntaxhighlight lang="C">
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180); //siehe nachfolgende Hinweise
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int ad_get(void) {
return 615; //614;
}
int main(int argc,char *argv[]) {
double alpha1=0.7071067811;
double alpha2=sin(45.0*M_PI/180);
printf("%f\n%f\n",alpha1,alpha2);
if(ad_get() > 614 ) printf("Sensor defekt\n");
if(ad_get() > (int)(3.0/(5.0/1023)+0.5) ) printf("Sensor defekt\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Ergänzend zu den oben aufgeführten Operatoren erlauben einige Compiler weitere Funktionen der Math.h Library in Konstantenausdrücken (z.B. sin(), cos(), ...)
* Konstanten Ausdrücke werden innerhalb des Compilers durch den Präprozessor ausgewertet, so dass dieser die Ergebnisse ebenfalls nutzen kann:
:<syntaxhighlight lang="C">
#define BUF_SIZE 512
#if (BUF_SIZE & (BUF_SIZE -1)) != 0
#endif
</syntaxhighlight>
=== String Konstanten ===
Stringkonstanten erzeugen ein Array von Characters. Mit dem abschließenden Hochkommata wird das Array um ein Stringendezeichen ergänzt:
<pre>
"abc" → (char []) {'a','b','c','\0'}
</pre>
Adjacent Strings Konstanten werden vom Compiler zu einer String-Kontante zusammengefasst, so dass nur ein Stringendezeichen vorhanden ist:
<pre>
"xxx" "yyy" → (char []) {'x','x','x','y','y','y','\0'}
</pre>
Über Prefixe können alternative Zieldatentypen/Konvertierungen erzwungen werden:
<pre>
L"string" → (wchar_t[7]){L's',L't',L'r' …)
</pre>
Über Postfixes können in C++ Objekte erzeugt werden:
<pre>
"string"s → erzeugt einen String vom Datentyp std::string
"string"sw → Erzeugt einen String vom Datentyp std::string_view
</pre>
String Konstanten werden Compilerintern über unnamed Variablen realisiert, welche als globale Variable angelegt werden und per default const sind:
<syntaxhighlight lang="C">
printf("Wert=%d",4);
//entspricht
const char unnamed1[]="Wert=%d";
printf(unnamed1,4);
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
printf("Wert=%d\n",4);
//entspricht
const char unnamed1[]="Wert=%d\n";
printf(unnamed1,4);
fflush(stdout); //Zur Darstellung der Ausgabe, da nachfolgend
//das Programm abstürzt und die gepufferte Ausgabe
//nicht zur Anzeige gebracht wird
//String Konstanten sind per Default Konstant
char *str="hallo"; //Typkonflikt!, da "hallo" vom Datentyp const char[] ist
str[0]='H'; //Laufzeitfehler, da nun schreibender Zugriff auf im
//Readonly Speicher angelegt Variable.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Für doppelte String Konstanten wird nur einmal Speicher reserviert:
<syntaxhighlight lang="C">
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2) printf("Identische Startadressen");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
const char *str1="hallo";
const char *str2="hallo";
if(str1==str2)
printf("Identische Startadressen");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Initialisierungsliste / Compound Literal ==
Arrays, Strukturen und Unions bestehen zumeist aus mehreren Elementen. Zur Initialisierung solcher Variablen werden die Initialisierungswerte in geschweiften Klammern als Initialisierungsliste zusammengefasst.
<code>
Syntax: {Initialisierungsliste}
</code>
Für eine Initialisierungsliste wird kein Speicher vorgehalten. Vielmehr wird bei der Variablendefinition die Variable direkt mit dem Inhalt der Liste initialisiert. Der Datentyp der Initialisierungsliste ergibt sich aus dem Datentyp der zu initialisierenden Variable:
<syntaxhighlight lang="C">
int arr[5] = { 1,2,3,4,5 };
struct xyz { int x,y,z;}; //Definition einer Struktur
struct xyz var = { 1,2,3 };
</syntaxhighlight>
Wird der Initialisierungsliste ein Datentyp in runden Klammern vorangestellt, so wird hiermit eine 'unnamend' Variable/Objekt, ein Compound Literal erstellt:
<code>
Syntax: (type) {Initialisierungsliste}
</code>
Ein Compound Literal entspricht einer anonymen Variablen des angegebenen Datentyps. Wie bei einer normalen Variablendefinition wird hier ebenfalls eine Variable angelegt und diese mit den Initialisierungswerten initialisiert. Im Unterschied zu einer normalen Variable kann auf solch eine Variable im Nachgang nicht mehr zugegriffen werden. Der Rückgabewert eines Compound Literals entspricht somit dem einer Variablen.</br>
Compound Literale bieten sich überall dort an, wo Variablen nur für einen einmaligen Zweck angelegt werden (bspw. bei der Parameterübergabe von Funktionen):
<syntaxhighlight lang="C">
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawline(struct point start,struct point end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start.x,start.y,end.x,end.y);
}
void printarray(int arr[4]) {
printf("[ ");
for(size_t idx=0;idx<4;idx++)
printf("%d ",arr[idx]);
printf("]\n");
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
struct point {int x; int y;};
drawline((struct point){1,2},(struct point){2,3});
printarray((int []){1,2,3,4});
//entsprechen
struct point unnamed1={1,2},unnamed2={2,3};
drawline(unnamed1,unnamed2);
int unnamed3[]={1,2,3,4};
printarray(unnamed3);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Über den Adressoperator kann auch die Adresse der anonymen Variablen ermittelt werden. In diesem Falle ist dann der Gültigkeitsbereich/-dauer des Compound Literals zu berücksichtigen. Wird eine Compound Literals außerhalb eines Block-Scopes angelegt, so entspricht sie einer globalen Variable, andernfalls einer lokalen Variablen. Außerhalb des Gültigkeitsbereiches verliert die Adresse auf solch eine Variable ihre Gültigkeit:
<syntaxhighlight lang="C">
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct point {int x,y;};
void drawlinep(struct point *start,struct point *end) {
printf("Linie von (%d,%d) nach (%d,%d)\n",start->x,start->y,end->x,end->y);
}
#include <stdlib.h>
int main(int argc,char *argv[]) {
drawlinep( &(struct point){1,2},&(struct point){2,3});
//entspricht
struct point unnamed1={1,2},unnamed2={2,3};
drawlinep( &unnamed1, &unnamed2);
struct point point1, *point2;
{ //Block-Scope, zwecks Darstellung von lokalen Variablen
point1= (struct point){1,2}; //Compound Literal entspricht hier
//Initialisierungswert für point1
point2=&(struct point){3,4}; //Compound Literal ist nur in diesem
//Block gültig
drawlinep(&point1 /*OK*/, point2 /*OK*/);
}
drawlinep(&point1 /*OK*/, point2 /*KO*/); //Zeiger zeigt auf nicht mehr
//gültigen Speicherbereich
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Compound-Literal sind per Default keine Konstanten, können also zur Laufzeit geändert werden (siehe Kap. [[Programmieren in C/C++: DatentypeSpecifier#Const Type Qualifier|DatentypeSpecifier:Const Type Qualifier]]):
:<syntaxhighlight lang="C">
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
float *arr=(float []){1.1,2.2,3.3}; //Kein Typkonflikt
arr[0]=47.11; //Änderung des 'Konstanten' arr[0] ist möglich
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweiften Klammern <code>{ }</code> sind nicht mit dem Block-Operator (siehe [[Programmieren in C/C++: Grundlagen#Block / Compound-Statement | Block / Compound-Statement]]) zu verwechseln. Werden die geschweiften Klammern bei der Initialisierung von Variablen genutzt, dann beschreibt der Inhalt der geschweiften Klammern eine Initialisierungsliste. Wird diesen ein Datentyp vorangestellt, dann wird hiermit eine Compound Literal definiert.
== Variableninitialisierung ==
Mit der Definition einer Variable kann diese optional initialisiert werden. Der tatsächliche Zeitpunkt der Variableninitialisierung (zur Laufzeit oder zur Compilezeit) und damit die Ausführung der Initialisierung (Maschinensprachebefehle oder Speichervorbelegung) hängt von der Gültigkeit/Sichtbarkeit der Variablen ab(siehe [[Programmieren in C/C++: Grundlagen#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]).
=== Globale + Static lokale Variablen ===
Globale und statisch globale Variablen werden in einem während der Laufzeit des Programms festen Speicherbereich gehalten. Zum Startzeitpunkt des Programms ist der Speicherplatz solch einer Variable mit dem Initialisierungswert gefüllt, so das bei erstmaliger Nutzung dieser Variablen diese ihre Initialisierungswerte enthalten. Die Belegung des Speicherplatzes erfolgt durch den Compiler, so dass als Initialisierungswerte / Inhalt der Initialisierungsliste nur Konstanten oder Konstanten-Ausdrücke (siehe [[Programmieren in C/C++: Grundlagen#Literale/Konstanten | Literale/Konstanten]]) erlaubt sind:
<syntaxhighlight lang="C">
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
double sin(double); //DJ: Include-Anweisung in wikibooks schlägt fehlt
int g=1; //Speicherstelle der Variable g wird
//mit 1 belegt
short array[3]={1,1+1, sin(0.0)}; //Speicherstellen des Arrays wird
//mit 1, 2 und 0 (Funktion sin() wird zur
//Compilezeit ausgeführt) belegt
int main(int argc,char *argv[]) {
printf("%hd %hd %hd\n",array[0],array[1],array[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Nicht initialisierte globale und static lokale Variablen werden mit 0 initialisiert! D.h. die Speicherstellen dieser Variablen werden mit dem Wert 0 vorbelegt::
<syntaxhighlight lang="C">
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int f; //f hat den Wert 0
double arr[10]; //Alle Elemente von arr werden mit 0.0 initialisiert!
int main(int argc,char *argv[]) {
printf("f=%d\n",f);
printf("%f %f %f\n",arr[0],arr[1],arr[2]);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Lokale Variable ===
Der Speicherplatz für lokale Variable wird auf dem Stack zur Verfügung gestellt. Mit jedem öffnenden Block-Scope wird Speicher für die innerhalb dies Block-Scopes vorhandenen Variablen vom Stack nach dem LIFO Prinzip reserviert und mit der Variablendefinition Maschinencode zur Initialisierung der Speicherstellen ausgeführt (sofern Variable einen Initialisierungswert hat):
<syntaxhighlight lang="C">
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für int) und 8 Bytes (für double)
int var1=12; //erzeugt Maschinencode zur Initialisierung
//der ersten 4 Byte mit dem Wert 12
double var2=sin(f); //erzeugte Maschinencode, welche zunächst
//die Funktion sin() mit dem Übergabewert f
//aufruft und dessen Rückgabewert in die
//nächsten 8 Byte des reservierten Speichers
//kopiert
...
{ //siehe zuvor
int var3=var1; //siehe zuvor
double var4=var2+var1;
} //siehe nachfolgenden
} //Freigabe des zuvor reservierten Speichers
</syntaxhighlight>
Dies gilt auch für Funktionsaufrufe. Mit der öffnenden geschweiften Funktionsklammer wird ebenfalls Speicher reserviert:
<syntaxhighlight lang="C">
void foo(int par)
{ //Öffnende Funktionsklammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Bytes (für (Übergabe)Variable par und 4 Bytes für Variable var
int var; //Da keine Initialisierung vorhanden ist wird auch
//kein Maschinencode zur Initialisierung ausgeführt
{ //Öffnende Klammer erzeugt Maschinencode zur Speicherreservierung
//von 4 Byte für Variable x
int x;
...
</syntaxhighlight>
Aufgrund der mit der Initialisierung bedingten Erzeugung von Maschinencode können die Initialisierungswerte/Inhalte der Initialisierungsliste bei lokalen Variablen aus beliebigen Ausdrücken bestehen und müssen keine Konstanten oder Konstanten Ausdrücke sein:
<syntaxhighlight lang="C">
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sin(f)}; //werden zur Laufzeit berechnet
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h> //fuer sinf()
void foo(float f,float g) {
float summe=f+g; //Initialisierungswerte
float arr[3] = {f+f,g-f,sinf(f)}; //werden zur Laufzeit berechnet
printf("%f\n",(double)summe);
printf("%f %f %f\n",(double)arr[0],(double)arr[1],(double)arr[2]);
}
int main(int argc,char *argv[]) {
foo(3,4);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dieser Maschinencode wird jedes Mal ausgeführt, wenn die dazugehörige Anweisung abgearbeitet wird und bedingt dementsprechend Rechenzeit. Zehnmaliges Ausführen einer Funktion oder zehnmaliges Öffnen eines Block-Scopes innerhalb einer For-Schleife führt zur zehnmaligen Ausführung der oben genannten Sachverhalte:
<syntaxhighlight lang="C">
void foo(int);
void var(void) {
for(int lauf=10; lauf>0; lauf--)
{ //zehnmaliges Reservieren von Speicher
int var=lauf*2; //zehnmalige Initialisierung
foo(var);
} //Freigabe des Speichers
}
void foo(int par) { //zehnmaliges Reservieren von Speicher
int var=12; //zehnmalige Initialisierung
} //Freigabe des Speichers
</syntaxhighlight>
Nicht initialisierte lokale Variablen werden nicht initialisiert, d.h. keine zusätzlichen Maschinenbefehle zum Initialisieren erzeugt. Der Variablenwert entspricht dann einem 'Zufallswert' oder korrekter gesagt dem Inhalt der Variablen, welcher zuvor der Speicherstelle zugewiesen war:
<syntaxhighlight lang="C">
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//und damit auch dessen zuletzt gültigen Wert
}
int main(int argc, char *argv[]) {
int var1=first(); //var1 beinhaltet Wert 7
int var2=second(); //var2 beinhaltet Wert 7
printf("var_foo=%d\n",var1);
printf("var_far=%d\n",var2);
return 0;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int first(void) {
int var_first=7;
return var_first;
}
int second(void) {
int var_second; //Variable var_second bekommt den identischen
return var_second; //Speicherbereich wie var_first zugwiesen
//(und damit auch dessen zuletzt gültigen Wert)
}
int main(int argc, char *argv[]) {
printf("%d\n",second()); //Zufallswert (0, da Stack mit 0 initialisiert ist)
printf("%d\n",first()); //Stack belegen
printf("%d\n",second()); //Zufallswert (7, da Speicherstelle zuvor mit 7
return 0; //belegt wurde)
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Wird eine Variableninitialisierung mit einer switch oder goto Anweisung übersprungen, so wird zwar die Variable angelegt (Speicherplatz reserviert), jedoch die Maschinenbefehle zur Initialisierung dieser Variablen nicht ausgeführt (siehe auch [[Programmieren in C/C++: Grundlagen# Switch-Anweisung|Switch-Anweisung]] und [[Programmieren in C/C++: Grundlagen# Label + Goto|Label + Goto]]). Die Variable enthält dann einen Zufallswert:
<syntaxhighlight lang="C">
switch(value) {
case 0:
int lok=7;
printf("%d",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(int value) {
switch(value) {
case 0:
int lok=7;
printf("%d\n",lok); //OK, lok beinhaltet den Wert 7
break;
default:
printf("%d\n",lok); //KO, Variable lok vorhanden,
//aber nicht initialisiert. D.h. Ausgabe einer
break; //Zufallszahl
}
}
void far(void) {
int var1=4711;
int var2=1799;
printf("Marke: %d, Erscheinungsjahr: %d\n",var1,var2);
}
int main(int argc,char *argv[]) {
foo(2); //Zufallswert (0, da Stack mit 0 initialisiert ist)
foo(0); //Initialisierungswert
far(); //Stack belegen
foo(2); //Zufallswert
return 0;
} | execCompilerOptions=|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei erstmaligem Funktionsaufruf kann eine nicht initialisierten lokale Variablen den Wert 0 beinhalten (Stackframe wird mit Programmstart auf 0 gesetzt). Beim nächsten Aufruf der Funktion ist zumeist die Speicherstelle der lokalen Variablen mit anderen Werten gefüllt worden, so dass nun ein anderer 'Zufallswert' als 'Initialisierungswert' enthalten ist
=== C++ ===
In C++ ist ergänzend die Initialisierung einer Variablen über () möglich. Bei Objekten wird hierüber der zugehörige Konstruktor aufgerufen. Bei primitiven Datentypen entspricht der Wert in den Klammern dem Initialisierungswert:
<syntaxhighlight lang="C++">
int variable(10); //Bei primitiven Datentype entspricht dies
//int variable=10;
struct test {
int a;
test(int par) {a=par;} //Konstruktor der Struktur test
};
struct test test(4); //Konstruktor test(int par) wird aufgerufen
struct test test(4,5); //KO, kein passender Konstruktor vorhanden
</syntaxhighlight>
=== Sonstiges ===
Folgende weitere Sachverhalten gilt es bzgl. Variableninitialisierung zu berücksichtigen:
* Nach C-Spezifikation ist eine Initialisierung von Variablen nicht notwendig. Es liegt folglich kein Fehler vor, wenn auf eine nicht initialisierte Variable lesend zugegriffen wird. Ungeachtet der C-Spezifikation überprüft der Compiler mit dem Schalter '-Wall' diesen Sachverhalt und gibt eine Warning aus
* Deklarationen/Prototypen können keinen Initialisierungswert enthalten
<syntaxhighlight lang="C++">
extern int var=7; //Fehlerhaft
</syntaxhighlight>
* Const und lokale Static Variablen sollten initialisiert werden, auch wenn C in diesem Fall keinen Fehler meldet!
<syntaxhighlight lang="C++">
const int konstante; //Syntaktisch OK, Initialisierungswert fraglich!
static int statisch;
</syntaxhighlight>
== Anweisung (Statement) & Expression ==
Eine Anweisung (Statement) stellt entsprechend dem Wikipedia Artikel {{w|Anweisung_(Programmierung) | Anweisung}} ''"ein in der Syntax einer Programmiersprache formulierte einzelne Vorschrift dar, die im Rahmen der Abarbeitung des Programms auszuführen ist"''.</br>
Aus der Statement Spezifikation ergibt sich folglich, welche Bestandteile ein Programm beinhaltet kann. In der C-Spezifikation [C11 6.8] sind folgende Anweisungen definiert:
: labeled-statement: Eine Sprungmarke für die Switch- und die Goto-Anweisung
: compound-statement: siehe nachfolgendes Kapitel
: expression-statement: siehe nachfolgendes Kapitel
: selection-statement: Eine if() oder switch() Anweisung
: iteration-statement: Eine while(), do while() oder eine for() Anweisung
: jump-statement: Eine goto, break, continue oder return Anweisung
so dass ein Programmablauf wie folgt aussehen könnte:
<syntaxhighlight lang="C">
int main(int argc, char argv[]) {
int var; //declaration innerhalb eines compound-statements
label: //labeled-statement
var=var*2+1; //expression-statement
for(var=0;var<100;var++); //iteration-statement
if(var<0) //selection-statement
printf("var<0"); //espression-statement
{ int lok=var; lok++; } //compound-statement
goto label; //jump-statement
return 0;
}
</syntaxhighlight>
=== Ausdruck (Expression) ===
Entsprechend der C-Spezifikation [C11 6.5] ist ein Ausdruck eine Folge von Operatoren und Operanden, die die Berechnung eines Werts angibt, ein Objekt oder eine Funktion bezeichnet, Nebenwirkungen erzeugt oder eine Kombination davon ausführt. Die Wertberechnungen der Operanden eines Operators werden vor der Wertberechnung des Ergebnisses des Operators ausgeführt (siehe auch {{w|lang=en|Expression_(computer_science)|Expression}}).
Beispiele:
<syntaxhighlight lang="C">
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöung der globalen Variable a)
int func(int par) { a++; return par*2;}
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
int a=0;
int func(int par) {
a++;
return par*2;
}
int main(int argc,char *argv[]) {
int a=4,b=7;
//Ausdruck ohne Nebenwirkung
a=sqrt(a*a+b*b);
//Ausdruck mit Nebenwirkungen (Erhöhung der globalen Variable a)
b=func(1)*func(2);
//Ausdruck mit undefinierten Verhalten (siehe später)
a=++a + 1;
//Statement (welches folglich keinen Rückgabewert hat)
//for-Statement beinhaltet jedoch 3 Ausdrücke (Initialisierungsteil,
//Testteil und Fortsetzungsteil)
a=for(int lauf=10;lauf>0;lauf--);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ausdrücke entsprechen somit Rechenvorschriften, die ausgewertet werden. Ausdrücke sind in C/C++ überall dort erlaubt, wo ein Operand erwartet wird:
<syntaxhighlight lang="C">
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func3(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf()]) {}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <math.h>
//Ausdruck innerhalb eines Funktionskopfes
int func1(int par) {
return 1;
}
int func2(void) {
return 1;
}
//Ausdruck innerhalb eines Funktionskopfes
void func3(int par, int arr[par*3*printf("func() called\n")])
{
printf("func() body\n");
}
int main(int argc,char *argv[]) {
int a=1;
//Ausdruck innerhalb der Parameterübergabe
func1(3*12*func2());
//Ausdruck innerhalb einer if/for/switch-Anweisung
if(a+1*3 > 3)
for(a=4*func1(12); 12*func2()<9; func1(a)*9);
switch( (a*3)&0x0f) {}
//Ausdruck innerhalb der Arraydefinition
int arr[1*3*13];
func3(1,arr);
return 0;
} | execCompilerOptions=-Wall -lm|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Dies ist unter anderen ein Grund dafür, dass C/C++ als unleserlich gilt. Zur besseren Lesbarkeit eines Codes sollte dieses 'Feature' nur dann genutzt werden, wenn es zwingend notwendig ist.
=== Discarded Value / null statement ===
Alle Ausdrücke und nicht void-Funktionen haben einen Rückgabewert, der weiter verwendet werden kann:
<syntaxhighlight lang="C">
a+7 //Rückgabewert ist das Ergebnis der Addtion
printf("hallo") //printf() Funktion ist vom Typ int und gibt die Anzahl
//der ausgegebenen Zeichen zurück
a //gibt den Inhalt der Variablen zurück
7 //gibt den 'Inhalt' der Konstanten zurück
b=(a=7) //der Zuweisungsoperator gibt den Zuweisungswert zurück
</syntaxhighlight>
Der letzte Rückgabewert eines fasst jeden Ausdruckes wird somit nicht genutzt. Dies wird Discarded Value bezeichnet:
<syntaxhighlight lang="C">
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
a; //Variable a wird gelesen, der Wert jedoch verworfen
7; //Konstante wird erzeugt und anschließend verworfen
a+7; //Ergebnis wird Berechnet und verworfen
printf("hallo"); //Rückgabewert von printf wird verworfen
a=a+7; //Die Zuweisung hat einen Rückgabewert, der verworfen wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der einfachste Fall eines Discarded Values ist ein Leeranweisung / null statement, d.h. die Anweisung besteht nur aus einem Semikolon. Dies stellt eine syntaktisch korrekte Anweisung dar, die keine Auswirkung hat:
<syntaxhighlight lang="C">
; //Leeranweisung
</syntaxhighlight >
Überall wo statements/Anweisungen erwartet werden (bspw. bei einer for-Schleife, bei einer if-Anweisungen) kann anstatt einer statements eine Leeranweisung stehen, welche dementsprechend nichts ausführt:
<syntaxhighlight lang="C">
for(size_t idx=0; str[idx]!=0; idx++)
; //Leeranweisung
while(a++ < 100)
; //Leeranweisungen
</syntaxhighlight>
An einige Stellen bietet sich die Nutzung dieser Sachverhalte als vorteilhaft an. Oft führen diese Sachverhalten jedoch zu Ausführungsfehlern, da sie aufgrund des korrekten Syntax vom Compiler nicht als Fehler gemeldet werden und beim Suchen dementsprechend nur schwer zu finden sind! Ggf. gibt der Compiler für einige Sachverhalte eine Warnung aus, so dass es vorteilhaft ist, Compiler-Warnings zu beachten!
Hinweise:
* Soll bewusst der Rückgabewert verworfen werden, so kann/sollte mit dem explizten Cast auf (void) der Rückgabewert explizit 'verworfen' werden. Dies ist u.A. hilfreiche bei Variablen, die (noch) nicht benutzt werden und der Compiler die Warning "unsued Variable" ausgibt:
:<syntaxhighlight lang="C">
(void)a; //Zur Vermeidung von Compiler-Warnings "Unused Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(void) {
return 4711;
}
int main(int argc,char *argv[]) {
int a;
(void)a; //Zur Vermeidung von Compiler-Warnings "Unsued Variable"
(void)(a+7); //hier eine explizte 'Ansage' der Verwerfung des Wertes
(void)func();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Mit der Anweisung <nowiki>[[nodiscard]]</nowiki> (ab C++17, ab C23) wird der Compiler angewiesen, dass der Aufrufer einer Funktion mit Rückgabewert der Rückgabewert entgegenzunehmen ist. Wird der Rückgabewert verworfen, so gibt der Compiler eine Fehlermeldung aus:
:<syntaxhighlight lang="C">
[[nodiscard]] int Client(int socket);
Client(5); ////Fehlermeldung, da Rückgabewert nicht verwendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
[[nodiscard]] int Client(int socket) {
return socket+1;
}
int Server(int socket) {
return socket+1;
}
int main(int argc,char *argv[]) {
Server(5); //keine Fehlermeldung
Client(5); //Fehlermeldung, da Rückgabewert nicht verwendet wird
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Sequence Point ===
Ein Sequenzpunkt (u.A. das abschließende Semikolon am Ende der Anweisung) ist nach dem Wikipedia Artikel {{w|lang=en|Sequence_point|Sequence Point}} definiert als der Punkt in der Ausführung eines Computerprogramms, an dem garantiert ist, dass alle Nebenwirkungen früherer Bewertungen durchgeführt wurden und noch keine Nebenwirkungen von nachfolgenden Bewertungen durchgeführt wurden.</br>
Sequenzpunkte führen somit zur Trennung der Abarbeitungsreihenfolge innerhalb von Ausdrücken. Das abschließende Semikolon am Ende eines Ausdruckes sorgt somit dafür, dass zunächst der vorangegangene Ausdruck abgearbeitet wird, bevor der nächste Ausdruck beachtet wird.</br>
Beschreibt das Semikolon explizit einen Sequenzpunkt, so gibt es auch andere Operatoren, die einen Sequenzpunkt beinhalten. Bei solchen Operatoren wird somit zunächst vollständig der erste Teilausdruck ausgewertet, bevor der nächste folgt. Zwei Beispiele für Operatoren mit Sequenzpunkt sind das logische Und <code>&&</code> und der <code>?</code>-Operator:
<syntaxhighlight lang="C">
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int func(int par) {
return printf("func(%d) called\n",par);
}
int main(int argc,char *argv[]) {
int a=0;
bool val = a++*5-1 && func(a);
//Der &&-Operator ist ein Sequenzpunkt, so dass zunächst
//der Ausdruck des linken Operators 'a++*5-1' vollständig berechnet wird,
//bevor der rechte Operator 'func(a)' ausgeführt wird.
//Wird beim logischen UND der linke Operator zu false ausgewertet,
//so kommt der rechte Operator nicht zur Ausführung!
int b=0,c=0;
c=c+++b*5+3 ? c++ : c--;
//Der ?-Operator beinhaltet zwei Sequenzpunkte. Zunächst wird
//der ganz linke Ausdruck 'c+++b*5+3 ausgewertet. Wird dieser
//zu TRUE ausgewertet, wird im Anschluss der mittlere Ausdruck 'c++'
//ausgewertet und der rechte Ausdruck 'c--' entfällt.
//Andernfalls wird nur der rechte Ausdruck ausgewertet
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein weiteres Beispiel ist der Komma-Operator. Hier teilt das Komma den Gesamtausdruck in mehrere Teilausdrücke auf, die nacheinander abgearbeitet werden (siehe
[[Programmieren in C/C++: Grundlagen#Komma-Operator | Komma-Operator]]).
=== Abarbeitungsreihenfolge ===
Die Abarbeitungsreihenfolge der Operatoren innerhalb eines Ausdruckes wird durch die Prioritätenliste/Rangfolge (siehe [[C-Programmierung: _Liste_der_Operatoren_nach_Priorität| C-Programmierung:Liste der Operatoren nach Priorität]]) vorgegeben. Operatoren mit höherer Priorität werden vor Operatoren mit niedriger Priorität ausgeführt. Die ()-Klammer hat die höchste Priorität:
<syntaxhighlight lang="C">
//Der Ausdruck
c = sizeof(x) + ++a / 3;
//wird aufgrund der Prioritäten wie folgt ausgewertet:
c= (sizeof(x)) + ( (++a) / 3);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=2;
int c;
int x=0;
c = sizeof(x) + ++a / 3;
printf("a=%d c=%d\n",a,c);
//Wird aufgrund der Prioritäten wie folgt ausgewertet:
a=2;
c= (sizeof(x)) + ( (++a) / 3);
printf("a=%d c=%d\n",a,c);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei identischer Priorität ergibt sich die Abarbeitungsreihenfolge aus der Assoziativität (L-R oder R-L):
<syntaxhighlight lang="C">
a=33 / 5 / 2;
//Wird aufgrund der L-R Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2;
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
a = b = c = d*2; //→ a=(b=(c=(d*2)));
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a;
a=33 / 5 / 2;
printf("a=%d\n",a);
//Wird aufgrund der Assoziativität wie folgt ausgewertet:
//a= (33 / 5) / 2
printf("a=%d\n",a);
//und damit zu 3 und nicht zu 16 (bei 33 / (5/2)) ausgewertet
int b,c,d=8;
a = b = c = d*2; //→ a=(b=(c=(d*2)));
printf("a=%d b=%d c=%d d=%d\n",a,b,c,d);
a = b = 1+c = d; //→ a=(b=((1+c)=d)); //Compilerfehler, da
//1+c kein lvalue ist
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
An einigen Stellen gibt die C/C++ Spezifikation die Abarbeitungsreihenfolge nicht vor (indeterminately-sequenced), überlässt diese somit dem Compiler:
* Bei Funktionsaufrufen ist die Abarbeitungsreihenfolge der Parameter nicht spezifiziert:
:<syntaxhighlight lang="C">
//Quelle: C-Spec Kap. 6.5.2.2
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int f1(void) {
printf("f1 called\n");
return 1;
}
int f2(void) {
printf("f2 called\n");
return 2;
}
int f3(void) {
printf("f3 called\n");
return 3;
}
int f4(void) {
printf("f4 called\n");
return 4;
}
void func1(int par1,int par2) {
printf("func1(%d,%d) called\n",par1,par2);
}
void func2(int par1,int par2) {
printf("func2(%d,%d) called\n",par1,par2);
}
int main(int argc,char *argv[]) {
//Quelle: C-Spec Kap. 6.5.2.2
void (*pf[2])(int,int)={func1,func2};
//Aufrufruf einer Funktion, deren Parameter sich aus Funktionsaufrufen
//ergeben
(*pf[f1()]) (f2(), f3() + f4()); //pf -> Array von Funktionszeigern
//Die Funktionen f1,f2,f3 und f4 können in einer beliebigen Reihenfolge
//aufgerufen werden
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Per Postinkrement/-dekrement Operator sagt aus, dass für die eigentliche Operation der Wert der Variablen genutzt wird und im Anschluss die Variable erhöht / erniedrigt werden soll. Nach C-Spezifikation [C11 6.5.2.4] muss dies spätestens vor dem nächsten Sequence Point erfolgt sein. Der genaue Zeitpunkt innerhalb des Sequence Points ist jedoch nicht vorgegeben:
:<syntaxhighlight lang="C">
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int a=7;
int b=a++ + a; //Ergebnis Abhängig, ob das Postinkrement vor oder
//nach der Addition ausgeführt wird.
a=a++ + 1; //dito
printf("a=%d b=%d\n",a,b);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Innerhalb einer Initialisierungliste ist Abarbeitungsreihenfolge nicht spezifiziert:
<syntaxhighlight lang="C">
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
struct abc {int a,b,c;};
struct abc var={var.c=1,var.a=2};
printf("var={a=%d b=%d c=%d}\n",var.a,var.b,var.c);
//Gerne anderen Compiler auswählen, z.B. x86-64 icc...
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Compound-Statement ===
Ein Compound-Statement ist innerhalb der C-Spezifikation ein alternativer Ausdruck für ein block-scope. Dieser fasst mehrere Statements und Deklarationen zu einem Statement zusammen:
<code>
Syntax: {Declaration-or-statement-list/textsuperscript<sub>OPT</sub>}
</code>
Ein Block wird nicht wie bei einer Anweisung mit einem Semikolon abgeschlossen (Das angehängte Semikolon wäre dann eine separate leere Anweisung!).
Ein Block hat blockweite Sichtbarkeit (siehe [[Programmieren in C/C++: Grundlagen#Blockweite Sichtbarkeit | Blockweite Sichtbarkeit]]), , so dass hier definierte Variablen nur hier gültig sind. Deklarationen sind ebenfalls nur in dem Block gültig:
<syntaxhighlight lang="C">
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void foo(void) {
int var1;
{ //Block innerhalb von Block als Strukturierungswerkzeug
int var1; //Var1 'überdeckt' var1 des äußeren Blockes
struct xyz{int x,y,z;}; //Defintion eines Datentyps im Block
struct xyz var3;
void far(void); //Prototyp
far();
}
struct xyz var4; //KO, Datentyp hier nicht mehr bekannt
far(); //KO, Prototyp hier nicht mehr bekannt
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Verwendung findet das Compound-Statement a) als Strukturierungsmöglichkeit innerhalb von Funktionen (zur Darstellung, dass dieser Bereich 'zusammengehörig' ist) und b) an den Stellen, an denen C/C++ nur eine Anweisung erwartet. Dies sind bspw. die If- und die For-Anweisungen:
<syntaxhighlight lang="C">
for(..) Anweisung; //For-Schleife führt nur diese eine Anweisung aus
for(…) {Block} //For-Schleife führt Block (als eine Anweisung) aus
if(..) Anweisung; else Anweisung; //IF-Anweisung führt nur 'eine'
//Anweisung aus
if(..) {Block} else {Block} //IF-Anweisung führt Block aus
if( ) {Block}; else {Block}; //Semikolon ist eine separate
//Leer-Anweisung, so dass else
//nicht zur IF-Anweisung zugeordnet
//werden kann (2 Anweisungen vor Else)</syntaxhighlight>
=== Embedded Statement ===
Embedded Statements sind eine GNU-C Erweiterung (siehe [https://www.gnu.org/software/gnu-c-manual/gnu-c-manual.html GNU-C-Manual 3.18]). Da diese vom Autor als sehr nützlich angesehen und auch von diversen Compilern und auch in C++ unterstützt werden, werden diese nachfolgend beschrieben.
Ein Compound-Statement fasst mehrere Anweisungen zu einer Anweisung zusammen, hat jedoch kein Rückgabewert. Ein Embedded-Statement entspricht einem Compound-Statement mit der Ergänzung, dass dieser einen Rückgabewert hat, so dass ein Embedded-Statement überall dort eingesetzt werden kann, wo eine Operand erwartet wird.
<code>
Syntax: ({Declaration-or-statement-list<sub>OPT</sub>})
</code>
Der Rückgabewert (und Datentyp) wird nicht über eine return-Anweisung angegeben, sondern entstammt aus dem Rückgabewert der letzten Anweisung innerhalb der Liste:
<syntaxhighlight lang="C">
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var;
var={int par=7;} //KO Block hat keine Rückgabewert.
var=({int par=7; par++; par;}); //OK Embedded-Statement hat einen
//Rückgabewert, der sich aus der
//letzten Anweisung 'Par;' ergibt
//Hier 8.
printf("var=%d\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Ein Embedded-Statement ähnelt folglich einem Funktionsaufruf mit dem Unterschied, dass a) in der Tat kein Funktionsaufruf stattfindet und b) der Rückgabewert nicht mit return, sondern über die letzte Anweisung zurückgegeben wird. Der Anwendungsfall ist dort zu finden, wo eine Operand erwartet wird und mehrere Anweisungen zum Ermitteln des Operanden notwendig sind:
<syntaxhighlight lang="C">
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc,char *argv[]) {
int var1=8;
int b=({int d=var1++;d>10?10:d;});
if( ({int d=b;b=var1;b=d;}) > 1)
printf("Bedingung erfüllt");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Ein Embedded-Statement ist insbesondere bei Nutzung von Makros (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]) hilfreich
* Mittels eines Embedded-Statement kann eine anonyme Funktion/Lambdafunktion dargestellt werden:
<syntaxhighlight lang="C">
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {return a%2?a:0;} ; func;})
,arr);
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
void test(int (*fptr)(int),int arr[10]) {
for(int lauf=0;lauf<10;lauf++)
arr[lauf]=fptr(arr[lauf]);
}
int main(int argc, char *argv[]) {
int arr[]={1,2,3,4,5,6,7,8,9,10};
//Aufruf mit einer anonymen Funktion
test( ({int func(int a) {printf("Called:%d\n",a);return a%2?a:0;} ; func;})
,arr);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Funktionen / Prozeduren ==
Funktionen/Prozeduren sind ein Strukturierungsmerkmal, so dass Teile der Funktionalität des Programmes wiederverwendbar sind. C/C++ unterscheidet nicht zwischen Funktionen (haben einen Rückgabewert, können damit als Operand in Ausdrücken verwendet werden) und Prozeduren (haben keine Rückgabewert, resp. Rückgabetyp void). <br/>
Mit jedem Aufruf einer Funktion wird für den zugehörigen Block ein eigener Stack-Kontext angelegt, so dass Funktionen sich selbst aufrufen können (Rekursion). Jeder Funktionsinstanz hat somit seinen eigenen lokalen Variablenbereich, teilen sich jedoch die globalen und die statisch lokalen Variablen.<br />
Mit dem Aufruf einer Funktion können Parameter übergeben werden, wobei die Übergabeparameter vom Aufrufer (Caller) durch den Aufruf in die lokalen Variablen des Aufgerufenen (Callee) kopiert/zugewiesen werden (Call by Value). Wird ein Zeiger übergeben, hat der Callee über die Dereferenzierung des Zeigers die Möglichkeit, die Variablen des Caller zu verändern (Call by Reference) (siehe Kap. [[Programmieren in C/C++: Zeiger #Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen).]]).
Hinweise:
* Die Klammerung hinter dem Funktionsnamen (<code>foo()</code>) zeigt an, dass es sich um einen Funktionsaufruf (Verzweigung der Programmausführung zu der Startadresse der Funktion) handelt:
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
foo(); //Klammern hinter dem Funktionsnamen bedeuten Aufruf der Funktion
</syntaxhighlight>
* Die Nutzung des Funktionsnamens ohne Klammerung (<code>foo</code>) gibt die Startadresse der Funktion zurück. Die Startadresse kann in einem Zeiger auf Funktionen gespeichert werden (siehe Kap. [[Programmieren in C/C++: Zeiger#Zeiger auf Funktionen | Zeiger:Zeiger auf Funktionen]]):
:<syntaxhighlight lang="C">
void foo(void) {printf("foo called");};
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
printf("foo called");
};
int main(int argc, char *argv[]) {
void (*fptr)(void)=foo; //Gibt Startadresse der Funktion zurück
//ohne diese aufzurufen
fptr(); //Aufruf der Funktion
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Deklaration/Definition vor dem ersten Aufruf der Funktion 'notwendig', damit Compiler die Übergabeparameter entsprechend bereitstellt und ggf. eine implizite Typkonvertierung durchführt (dito Rückgabewert). Die Angabe der Variablennamen können bei der Deklaration entfallen
* Die fehlende Angabe der Übergabeparameter bedeutet in C (bis einschl. C18), dass diese Funktion mit beliebigen Übergabeparametern aufgerufen werden kann und der Compiler keine Typprüfung durchführt:
:<syntaxhighlight lang="C">
int func(/*Keine Übergabeparameter angegeben*/) {...}
//kann wie folgt aufgerufen werden
func();
func(4);
func("hallo Welt",4.7);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func() {
printf("foo called\n");
};
int main(int argc, char *argv[]) {
func();
func(4);
func("hallo Welt",4.7);
//Ab C23 hat sich die Bedeutung geändert.
//Zum Testen C-Versionsvorgabe -sdc=xxx unter Compiler-options aendern
return 0;
} | execCompilerOptions=-Wall -std=c17|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:→ unbedingt vermeiden<br />
:Hat die Funktion keinen Übergabewert, so wird dies in C mit void gekennzeichnet
* In C++ bedeutet die Schreibweise ohne Datentypbeschreibung, dass keine Parameter erwartet werden
* In der Parameterliste von Funktionen dient in der GNU-C Spezifikation das Semikolon zum Trennen zwischen Deklaration von Übergabeparameter und den Übergabeparametern. Alle Übergabewerte links vom Semikolon sind (Forward)deklarationen:
:<syntaxhighlight lang="C">
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Aufruf
test1(3,7); //a=7 b=3
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim);
//Aufruf
test2("hallo",6);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void test1(int a; int b,int a) {
// Forward; Parameter
printf("a=%d b=%d\n",a,b);
}
//Sinnvoll im Umgang mit Variable Length Arrays
void test2(int dim; const char str[dim], int dim) {
printf("dim=%d\n",dim);
}
int main(int argc, char *argv[]) {
//Aufrufe
test1(3,7); //a=7 b=3
test2("hallo",6);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Return-Anweisung ===
Mit der Return-Anweisung wird eine Funktion (vorzeitig) beendet. Der optionale Parameter dient der Angabe des Rückgabewertes der Funktion an den Aufrufer. Der Datentyp des Parameters ergibt sich aus dem Rückgabedatentyp der Funktion.
<code>
Syntax: return expression<sub>OPT</sub>
</code>
Der Rückgabewert expresion sagt aus, dass hier nicht nur Konstanten oder Variablen stehen können, sondern ein komplexer Ausdrücke erlaubt ist. Der resultierende Datentyp des Ausdruckes sollte dem Rückgabedatentyp der Funktion entsprechen, andernfalls wird eine implizite Typkonvertierung vollzogen (sofern möglich):<syntaxhighlight lang="C">
int foo(double a, double b) {
return (int)(a*a+b*b);
}
</syntaxhighlight>
Hinweise:
* Bei nicht void-Funktionen ist eine return-Anweisung mit einer Expression entsprechend dem Datentyp der Funktion zwingend notwendig:
:<syntaxhighlight lang="C">
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
double a=func(); //int wird in double konvertiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int func(void) {
return 5.1; //Datentyp wird zuvor int konvertiert
}
int main(int argc, char *argv[]) {
double a=func(); //int wird in double konvertiert
printf("a=%f\n",a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei einer void-Funktion ist die return-Anweisung ohne Expression optional. Hier entspricht der schließende Block der Return-Anweisung
:<syntaxhighlight lang="C">
void func(char *str) {
if(str==NULL)
return;
printf("%s",str);
}
</syntaxhighlight>
Sollen mehr als ein Rückgabewert an den Aufrufer zurückgegeben werden so empfiehlt sich:
* die Rückgabewerte in einer Struktur zu packen (siehe [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++) |Datentypen:Verbundtyp Struktur/Klasse (nur C++)]])
* die Rückgabewerte über die Aufrufparameter als Call-by-Reference zu übergeben (siehe [[Programmieren in C/C++: Zeiger#Zeiger bei Funktionsaufrufen | Zeiger:Zeiger bei Funktionsaufrufen]])
==== Rückgabewert aus Datentypsicht ====
Aus Datentypsicht kann der Funktionsname inkl. den Parameter(n) in einem Ausdruck mit dem Datentyp des Rückgabewertes der Funktion ausgetauscht werden:
<syntaxhighlight lang="C">
int foo(void) {return 4711;}
int var;
var=1+foo(); //Aus Datentypsicht (int)=(int)+(int)
</syntaxhighlight>
Daraus ergibt sich, dass bei Arrays/Strukturen/Unions direkt auf einzelne Komponenten zugegriffen werden kann, ohne diese zuvor einer Variablen zuzuweisen:
<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
if(foo(12).x == 12) printf("Identisch\n");
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
if(far(3)[2] == 2) printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
#include <stdlib.h>
struct xyz{int x,y,z;};
struct xyz foo(int par) {
struct xyz var;
var.x=var.y=var.z=par;
return var;
}
int *far(size_t par) {
int *ret=malloc(par*sizeof(int));
for(size_t lauf=0;lauf<par;ret[lauf]=lauf,lauf++);
return ret;
}
int main(int argc, char *argv[]) {
if(foo(12).x == 12)
printf("Identisch\n");
if(far(3)[2] == 2)
printf("Identiisch\n");
//Hinweis: Funktion erzeugt aufgrund des fehlenden free's
//ein MemoryLeak
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
==== Fehlerrückgabe ====
Viele Funktionen können unter gewissen Umständen nicht korrekt ausgeführt werden. Z.B. aufgrund dessen, dass:
* der benötigter Speicher vom Heap nicht bereitgestellt werden kann
* Übergabeparameter außerhalb des zulässigen Wertebereiches liegen
* angeforderte Ressource (Datei, Geräte, …) nicht vorhanden/verfügbar sind
Solche Fälle gilt es dem Aufrufer mitzuteilen, da in diesen Fällen die vom Aufrufer geforderte Funktionalität nicht erfüllt ist und der Aufrufer ggf. nicht weiterarbeiten kann. Zur Mitteilung des Fehlers sollte vorrangig der Rückgabewerte genutzt werden. (auch wenn in C++ mit Exception eine Alternative hierzu bereitsteht)
<syntaxhighlight lang="C">
char *strdup(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *strdup1(char *src) {
char *dst;
if((dst=malloc(strlen(src)+1))==NULL)
return NULL;
strcpy(dst,src);
return dst;
}
int main(int argc, char *argv[]) {
char *dup=strdup1("hallo");
if(dup == NULL)
printf("Fehler\n");
else
printf("dup='%s'\n",dup);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Standard-C Library-Funktionen geben in diesem Fall zumeist ein -1 (Rückgabewert Ganzzahl) oder einen NULL-Zeiger (Rückgabewert Zeiger) zurück. Der genaue Fehlergrund ist dann ergänzend in der globalen Variablen errno gespeichert. Mittels der Standard-C Funktion strerror() kann die Zahl in einen für den Anwender/Programmierer lesbaren String umgewandelt werden (die GNU-C Library Funktion printf() bietet ergänzend den Conversion Spezifier %m als alternative Ausgabemöglichkeit an):
<syntaxhighlight lang="C">
#include <errno.h>
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int var;
if(-1==scanf("%d",&var) ) printf("Es wurde keine Zahl erkannt\n");
int ret=open("/etc/ptmp",O_WRONLY{{!}}O_CREAT{{!}}O_EXCL,
S_IRUSR{{!}}S_IWUSR{{!}}S_IRGRP{{!}}S_IROTH);
if(-1==ret)
printf("open failed() with %s\n",strerror(errno));
if(-1==ret)
printf("open failed() with %m (nur glibc)\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'''Für eine sauber Programmierung sollte diese Methodik generell angewendet werden.''' Jede Funktion, welche Fehlschlagen kann, teilt dies per Rückgabewert dem Aufrufer mit. Der Rückgabewert einer jeden Funktion wird vom Aufrufer kontrolliert.
=== Main-Funktion ===
Mit Start der Anwendung übergibt das Betriebssystem die Kontrolle an die Anwendung und führt dort die Funktion main aus. Als Übergabe- und Rückgabeparameter sind folgende Varianten erlaubt:
<syntaxhighlight lang="C">
int main(void) { }
int main(int argc, char *argv[]) { }
</syntaxhighlight>
Mit dem Start der Anwendung kann, wie bei jedem Funktionsaufruf, Parameter an den startenden Prozess übergeben werden. Die Parameter werden als Array von Strings übergeben. Im Parameter argc ist die Anzahl der Strings enthalten. Im Parameter argv[0..argc-1] sind die einzelnen Strings enthalten. Sofern vorhanden ist im ersten String der Programmname/Aufrufname der Anwendung enthalten:
<syntaxhighlight lang="C">
int main(int argc, char *argv[]) {
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++)
printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int max_width=0;
int ret;
//Variante 1: Darstellung des Inhaltes des Arrays von Strings
for(int lauf=0;lauf < argc; lauf++) {
ret=printf("%d.Parameter: '%s'\n",lauf,argv[lauf]);
max_width=ret>max_width ? ret : max_width;
}
//Trennzeichen drucken
char term[max_width];
memset(term,'-',max_width);
printf("%.*s\n",max_width-1,term);
//Variante 2: Darstellung des Inhaltes des Arrays von Strings
(void)argv; //Wird hier nicht benötigt
for(char **str=argv;*str!=NULL;str++)
printf("Parameter: '%s'\n",*str);
return EXIT_SUCCESS;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Im Compiler-Explorer können die Parameter im Executor unter 'Execution Arguments', getrennt mit Leerzeichen eingegeben werden.
Wird die Funktion main beendet, entweder über die return Anweisung oder den Aufruf der exit() Funktion, wird die Kontrolle zurück an den startenden Prozess (zumeist Shell) gegeben. Über den Rückgabewert wird im Allgemeinen dem Aufrufer der Fehlerstatus mitgeteilt (EXIT_SUCCESS oder 0 bedeutet fehlerfreie , EXIT_FAILURE oder Werte ungleich 0 fehlerhafte Ausführung).
Hinweise:
* Der Return-Wert der main-Funktion kann mit >>echo $? in der Bash abgefragt werden
* Mittels <code>exit(int status)</code> kann das Programm an jeder Stelle innerhalb des Programms beendet werden. <code>status</code> entspricht dann der expression der return Anweisung von main()
* Ungeachtet des Rückgabedatentyps int bei der Defintion der main() Funktion beträgt der zulässige Wertebereich für Linux Anwendungen 0..255. Der korrekte Rückgabedatentyp der main() Funktion müsste somit 'unsigned char' lauten
=== Inline Funktion ===
Wie der Name inline andeutet, ist die Intention von Inline, dass die aufgerufen Funktion Bestandteil der aufrufenden Funktion ist. Die aufgerufene Funktion soll somit im Kontext des Aufrufers ausgeführt werden, so dass kein eigener Stack bereitgestellt werden muss. Der Start der Funktion kann somit schneller erfolgen:
<code>
inline int foo(void) { }
</code>
Das Funktionseinbindung/zusammenführung erfolgt durch den Compiler (und nicht durch den Linker). Damit das inline vom Compiler ausgeführt werden kann, muss die zu inlinende Funktion vor dem Aufruf definiert sein, d.h. sie muss in derselben C-Datei oder in einer der einzubindenden Header-Dateien enthalten sein [C11 6.7.4].
Hinweis:
* Das 'inlinen' von Funktionen über die eigene Objektdatei hinweg erfolgt in C/C++ über Link Time Optimization (LTO). Hierzu fügt der Compiler den Zwischencode mit in die Objektdatei, so dass der Linker das 'inlinen' vollziehen kann (siehe {{w|lang=en|Interprocedural_optimization| Interprocedural Optimization}})
=== Variadic Function / Ellipsis Punctuator ===
Mit dem Ellipsis Puncturator '…' kann in Funktionsdefinitionen angegebenen werden, dass an dieser Stelle beliebig viele Parameter/Argumente übergeben werden können. Dies wird unter anderen in der printf() Anweisung genutzt:
<syntaxhighlight lang="C">
int printf(const char *fmt, ... );
</syntaxhighlight>
Die wie folgt aufgerufen werden kann:
<syntaxhighlight lang="C">
printf("Hello World"); //es folgt kein Parameter
printf("%d",100); //es folgt ein Parameter vom Datentyp int
printf("%f",1.1); //es folgt ein Parameter vom Datentyp double
printf(conststr,1,2,3,"xyz") //Ohne Worte
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
printf("Hello World\n"); //es folgt kein Parameter
printf("%d\n",100); //es folgt ein Parameter vom Datentyp int
printf("%f\n",1.1); //es folgt ein Parameter vom Datentyp double
const char *conststr="%d %x %c '%s'\n";
printf(conststr,1,2,33,"xyz"); //Ohne Worte
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Bei der Parameterübergabe wird der Datentyp nicht mit übergeben, so dass die aufgerufene Funktion keine Möglichkeit hat, den Datentype der Parameter zur Laufzeit zu ermitteln. Einzig werden bei Aufruf der variadischen Funktion so viel Bytes auf den Stack gelegt, wie der Datentyp der einzelnen Übergabeparameter groß ist:
:<code>int --> 4 Byte</code>
:<code>double --> 8 Bytes</code>
:<code>Zeiger --> 4/8 Byte</code>
Damit die aufgerufene Funktion die fehlende Datentypinformation dennoch mitgeteilt bekommt, erfolgt dies am Beispiel der printf Funktion über den Format-String:
<syntaxhighlight lang="C">
int vari;
printf("%d",vari); //%d erwartet einen Integer Übergabeparameter (4-Byte)
size_t vars;
printf(" %zu %d ", vars, vari); // %zu zur Mitteilung, dass anstatt
//integer nun size_t als Datentyp übergeben wird
//und somit anstatt 4 Bytes 8 Bytes vom Stack genommen werden
</syntaxhighlight>
<code>printf()</code> entnimmt entsprechend der Datentypbeschreibung im Formatstring die passende Anzahl an Bytes vom Stack.
Da der Compiler für die optionalen Parameter nicht den Zieldatentyp kennt, erlaubt die C-Spezifikation als Übergabedatentypen hier nur die Grunddatentypen <code>signed int, unsigned int, long, long long, double</code> und <code>Zeiger</code>. Entspricht der übergebene Parameter nicht einen dieser Datentypen, so wird er mittels implizit Cast entsprechend nachfolgender Tabelle gewandelt [C11 6.5.2.2 Default Argument Promotions]:
{| class="wikitable"
|-
! Ausgangstyp !! Umwandlungstyp
|-
| char, signed char, short || int
|-
| unsigned char, unsigned short || unsigned int
|-
| float || double
|-
| Alle anderen Datentypen || bleiben erhalten
|}
Bspw.:
<syntaxhighlight lang="C">
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Über den Length-Modifier Parameter im Formatstring kann printf mitgeteilt
//werden, dass von dem übergebenem Integerwert weniger Bytes zu
//interpretieren sind
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
signed char varc=-1;
float varf =0.1;
printf("%d %f",varc, varf); //varc wird beim Aufruf nach int konvertiert!
//varf wird beim Aufruf nach double konvertiert!
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
Zum Umgang mit dem variadischen Parameter stellt C die Funktionen <code>va_start(), va_arg(), va_copy()</code> und <code>va_end()</code> bereit. Auf Grundlage des dazugehörigen Datentyps <code>va_list</code> können variadische Parameter auch an Unterfunktionen weitergereicht werden (bspw vprintf()). Dieses Thema bedingt jedoch genaue Kenntnisse vom Umgang mit dem Stack und ist nicht Bestandteil dieser Vorlesung.
=== Funktion in Funktion ===
Die GNU-C Reference (nicht C++) erlaubt es, Funktionen innerhalb von Blöcken (und damit innerhalb von Funktionen) zu definieren. Diese innere Funktion steht dann nur in diesem Block zur Verfügung und kann von außerhalb des Blockes nicht aufgerufen werden. Als Gimmick können Funktionen in Funktionen auf die zuvor definierten lokalen Variablen der inkludierenden Funktion zugreifen:
<syntaxhighlight lang="C">
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(void) {
{
int label=1;
//Funktion innerhalb einer Funktion
void dummy(void){
label++; //Zugriff auf Variablen des umschließenden Blockes
}
dummy(); //Aufruf der nur in diesem Block gültigen Funktion
}
dummy(); //KO, Funktion hier nicht mehr gültig
}
int main(int argc,char *argv[]) {
foo();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Variable Length Array (VLA) ==
Im Normalfall ergibt sich die Anzahl der Elemente eines Arrays aus einer Konstanten, so dass der Compiler zur Compilezeit passend Speicher reserviert (siehe Kap. [[Programmieren in C/C++: Array | Array]]):
<syntaxhighlight lang="C">
int arr[4]; //Compiler reserviert für Variable arr
//4*sizeof(int) Speicherplatz
</syntaxhighlight>
Bei Variable Lenght Array wird die Arraydimension nicht über eine Konstante, sondern über eine Variable oder einen Ausdruck angegeben. D.h. die tatsächliche Dimension des Arrays ergibt sich erst zum Ausführungszeitpunkt der Definition:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //Arraydimension ergibt sich zum Ausführungszeitpunkt
n++; //Nachträgliches Ändern von n ändert nicht
//die Größe des Arrays!
}
</syntaxhighlight>
Ein Variable Length Array kann nur als lokale Variable oder als Übergabeparameter definiert werden (wobei im letzteren Fall kein Speicher hiermit reserviert wird). Eine Initialisierung eines VLA's mit der Definition ist nicht möglich, d.h. nach der Definition beinhaltet das Array 'zufällige' Werte. Es empfiehlt sich daher, diese bspw. mit memset händisch zu initialisieren (siehe auch Kap [[Programmieren in C/C++: Array#Initialisierung | Array:Initialisierung]]):
<syntaxhighlight lang="C">
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
void foo(size_t n) {
char str[n];
memset(str,0,n*sizeof(char)); //Array mit 0 füllen
for(size_t lauf=0;lauf<n;lauf++)
printf("str[%zu]=%d\n",lauf,str[lauf]);
}
int main(int argc, char *argv[]) {
foo(4);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Mittels sizeof kann weiterhin der Speicherbedarf ermittelt werden, wobei sizeof mit einem VLA als Argument kein Konstantenausdruck ist. Stattdessen wird die Größe zur Laufzeit ermittelt:
<syntaxhighlight lang="C">
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void foo(size_t n) {
int arr[n*2+1]; //VLA
size_t size;
size=sizeof(arr); //sizeof(arr) entspricht einem Funktionsaufruf
//welcher die Speichergröße des VLA's ermittelt
printf("size=%zu\n",size);
}
int main(int argc, char *argv[]) {
foo(5);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
VLA wurden erstmals in C mit C99 eingeführt. In C11 wurden VLA's als optional eingestuft und mit C23 zurück auf notwendig gesetzt. In C++ sind VLA's nicht definiert, werden jedoch vom GCC Compiler unterstützt. Als alternativen Datentyp wird hier std::array empfohlen.
Hinweis:
* VLA sind nicht direkt in einem Switch-Case Block definierbar. Wird hier ein VLA benötigt, so muss hierzu ein Block erzeugt werden:
:<syntaxhighlight lang="C">
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int value=argc;
switch(value) {
case 1:
char arr1[value]; //Compilerfehler, da bei value!=1 kein Speicherplatz
//für das VLA reserviert wird
break;
case 2: {
char arr2[value]; //OK
}
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Operatoren ==
In der Programmiersprache C sind folgende Punctuators [C11 6.4.6] definiert:
<syntaxhighlight>
[ ] ( ) { } . ->
++ -- & * + - ~ !
/ % << >> < > <= >= == != ^ | && ||
? : ; ...
= *= /= %= += -= <<= >>= &= ^= |= , # ##
<: :> <% %> %: %:%:
</syntaxhighlight>
Die Funktionalitäten sind identisch zu Java. Aufgrund des Datentyps Zeiger gibt es in C ergänzend den Punctuator <code>-></code> (siehe Kap [[Programmieren in C/C++: Datentypen#Verbundtyp Struktur/Klasse (nur C++)|Datentypen:Verbundtyp Struktur/Klasse (nur C++)]]). Der Präprozessor bedingt die beiden Punctuatoren <code>#</code> und <code>##</code> (siehe Kap [[Programmieren in C/C++: Präprozessor | Präprozessor]]).
Die letzten 6 Punctuators <code><: :> <% %> %: %:%:</code> werden zu <code>[ ] { } # ##</code> ersetzt. Sie sind für Computersysteme gedacht, welche keine ALTGR-Taste besitzen.<br />
Java kennt ergänzend den <code>>>></code> Operatoren, welcher in C über den normalen Schiebebefehl und den zugrundeliegenden Datentyp gesteuert wird.
Wie in Java sind einige Punctuators vom Kontext abhängig und haben damit unterschiedliche Funktionalitäten:
<syntaxhighlight>
++ → (Postfix) ++ vs. ++(Präfix)
-- → (Postfix) -- vs. --(Präfix)
+/- → Vorzeichen vs. Addition/Subtraktion
() → Funktionsaufruf() vs. Befehlsbestandteil if() vs. Priorisierung
</syntaxhighlight>
Für den Umgang mit dem Datentyp Zeiger besitzen einige Punctuatoren ergänzende Funktionalitäten (siehe Kap [[Programmieren in C/C++: Zeiger| Zeiger]]):
<syntaxhighlight>
& → Bitweises UND:
Anwendung: Ganzahlausdruck & Ganzahlausdruck
& → Adressoperator:
Anwendung: &Variable
* → Multiplikation
Anwendung: Ganzahl-/Gleitkommaausdruck * Ganzahl-/Gleitkommaausdruck
* → Datentyp Zeiger
Anwendung: Datentyp * Variablenname;
* → Dereferenzierung:
Anwendung: * Zeiger
</syntaxhighlight>
Punctuatoren, welche von Java abweichende / ergänzende Funktionalitäten haben, werden nachfolgend gesondert beschrieben.
Sind in einer Anweisung mehrere Operatoren enthalten, so hängt die Abarbeitungsreihenfolge von der Rangfolge/Priorität der Operatoren ab (siehe [[Programmieren in C/C++: Grundlagen#Abarbeitungsreihenfolge | Abarbeitungsreihenfolge]]).<br />
Die Rangfolge ist identisch zu Java, wobei C mehr Operatoren kennt. Generell empfiehlt sich, lieber eine Klammer zu viel als zu wenig zusetzen. Klammern haben die höchste Priorität.
=== Zuweisungs-Operator ===
Die Zuweisung ('='-Operator, assignment expression) weist dem L-Value den R-Value zu.
Der Zuweisungs-Operator gibt den L-Value als Rückgabewert der Zuweisung zurück, so dass mehrere Zuweisungen in einem Ausdruck möglich sind. Die Abarbeitungsreihenfolge ist von rechts nach links (R-L Assoziativität). Wird der 'letzte' Rückgabewert nicht verwendet, so wird dieser verworfen (siehe Kap. [[Programmieren in C/C++: Grundlagen#Discarded Value / null statement | Discarded Value / null statement]]).<br />
Beispiel:
<syntaxhighlight lang="C">
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
//der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
//Compilerfehler geworfen wird
x*=y=z //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a,b,c=3,d=4;
int x,y,z;
a=7; //Zuweisung
a=b=7; //Erste Zuweisung (b=7) hat einen Rückgabewert, welcher im
//Anschluss a zugewiesen wird
if(a=7) //Variablen a wird der Wert 7 zugewiesen. Der Rückgabewert
; //der Zuweisung wird im Anschluss auf True oder False geprüft
if(7=a) //Besser, da aufgrund der fehlerhafter Zuweisung ein
; //Compilerfehler geworfen wird
x*=y=z; //entspricht x=x*(y=z)
a=b=d+7; //entspricht a=(b=(d+7))
a=b==c; //a bekommt das boolesche Ergebnis der Vergleichsoperation
//zugewiesen return 0;
a=7+b=8; //Fehler, da der Zuweisungs-Operator die zweitniedrigste Priorität hat
//Abarbeitungsreihenfolge: a=(7+b)=8 -> 7+b kann keinen Wert zugewiesen werden
a=7+(b=8);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* Auf beiden Seiten der Zuweisung muss der identische Datentyp stehen. Wenn andernfalls eine implizite Typkonvertierung nicht möglich ist, gibt der Compiler einen Fehler aus:
:<syntaxhighlight lang="C">
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a = 7.3; //implizite Typkonvertierung
double b=a+3; //Implizite Typkonvertierung der Intergeraddition nach double
float c=(float)a+(float)3; //Explizite Typkonvertierung
char *d=a; //Compilerfehler, da Integerwert nicht implizit in einen
//Zeiger konvertiert werden kann
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
(void)b;
(void)c;
(void)d;
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
* Bei der Parameterübergabe beim Funktionsaufruf wird ebenfalls indirekt der Zuweisungs-Operator angewendet. Die Parameter des Aufrufers werden per Zuweisung den lokalen Variablen der aufgerufenen Funktion zugewiesen
:<syntaxhighlight lang="C">
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int a, float b) {
printf("a=%d b=%f",a,b);
}
int main(int argc, char *argv[]) {
int x=4;
float y=5.0;
func(x,y); //der Inhalt der Variablen x wird der lokalen Variable a
//(a=x) und der Inhalt der Variablen y der lokalen Variablen b
//(b=y) zugewiesen.
func(y,x); //Dito, mit der Ergänzung, dass eine implizite Typkonvertierung
//stattfindet (a=(int)y) und (b=(float)x).
//Zur Darstellung der besagten Konvertierung siehe rechtes Fenster
return 0;
} | execCompilerOptions=-Wall|
h=g
}} Öffnen im Compiler Explorer] }}
=== Komma-Operator ===
Der Komma-Operator erlaubt es, zwei Ausdrücke auszuführen, wo nur einer erlaubt wäre. Die Ergebnisse/Rückgabewerte aller durch diesen Operator verknüpften Ausdrücke, außer dem letzten werden verworfen. Der letzte Ausdruck dient als Rückgabewert.
Folgendes gilt es bei der Nutzung des Komma-Operators zu beachten:
* Der Komma-Operator wird von links nach rechts ausgewertet (L-R Assoziativität)
* Das Komma selbst stellt eine Sequence Point dar (siehe Kap [[Programmieren in C/C++: Grundlagen#Sequence Point|Sequence Point]])
* An Stellen, wo das Komma zum Syntax gehört (z.B. Trennung der Übergabeparameter bei der Funktionsdefinition und beim Funktionsaufruf, Trennung von Variablen bei der Variablendefinition/-deklaration, Trennung der enum Konstanten) muss der Ausdruck ergänzend geklammert werden, wenn der Komma-Operator gefordert ist
* Der Komma-Operator hat von allen Operatoren die niedrigste Priorität/Rangfolge, so dass dieser Operator als letztes 'ausgewertet' wird
Beispiel:
<syntaxhighlight lang="C">
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da das Komma hier zur Trennung der Variablen dient
//und nicht als Komma-Operator fungiert
int c=1,d=2,e=3;
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
void func(int value){}
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
void func(int value){
printf("func called with %d\n",value);
}
int main(int argc, char *argv[]) {
int a=(5,3); //5 wird verworfen, 3 dient als Rückgabewert, so dass
//a den Wert 3 erhält.
int b=5,3; //KO, da das Komma hier zur Trennung der Variablen dient
//und nicht als Komma-Operator fungiert
printf("a=%d\n",a);
int c=1,d=2,e=3;
printf("c=%d,d=%d,e=%d\n",c,d,e);
int f=(c+=2,a+a); //c um zwei erhöht, a+a in f
printf("c=%d,f=%d\n",c,f);
int g= c+=2,a+a; //KO, da Komma Bestandteil der Defintion ist
func(1); //Funktion wird mit dem Wert 1 aufgerufen
func(1,2); //KO, da Komma Bestandteil des Funktionsaufrufes ist
func((1,2)); //Funktion wird mit dem Wert 2 aufgerufen
int arr[12];
arr[3,4]=1; //3 wird verworfen, 4 dient als Index für das Array
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
'Sinnvolle' Anwendungsbeispiele:
* Bei For-Schleifen, so dass mehrere Variablen initialisiert und mehrere Variablen mit jedem Schleifendurchlauf geändert werden können:
:<syntaxhighlight lang="C">
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf]);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int sum,lauf;
int arr[]={5,4,3,2,1};
for(sum=100,lauf=5 ; lauf ; lauf--,sum+=arr[lauf])
printf("sum=%d lauf=%d\n",sum,lauf);
printf("sum=%d\n",sum);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der Return-Anweisung, bei welcher zur Darstellung der Zusammengehörigkeit mehrere Aktionen ausgeführt werden sollen:
:<syntaxhighlight lang="C">
return errno=EINVAL,-1;
return printf("Fehler"),-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <errno.h>
int foo(void) {
return errno=EINVAL,-1;
}
int far(void) {
return printf("Fehler\n"),-1;
}
int main(int argc, char *argv[]) {
printf("foo()=%d\n",foo());
printf("far()=%d\n",far());
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* An Stellen, wo nur eine Anweisung erlaubt ist (und man zu faul ist, einen Block zu öffnen)
:<syntaxhighlight lang="C">
if(…) y=2,z=3;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int y=0,z=0;
if(1) y=2,z=3;
printf("y=%d z=%d\n",y,z);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In vielen Ländern wird das Komma zur Darstellung von Gleitkommazahlen genutzt. Wird versehentlicher Weise dies in C/C++ übernommen, so führt dies zu einem unerwarteten Verhalten:
:<syntaxhighlight lang="C">
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
double var;
var=5.3; //Variable wird mit 5.3 initialisiert
printf("var=%f\n",var);
var=5,3; //KO, da Komma Bestandteil der Defintion ist
var=(5,3); //Variable wird mit 3 initialisiert
printf("var=%f\n",var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== ?-Operator / Conditional-Operator ===
Operator mit 3 Operanden, welcher in Abhängigkeit des ersten Operanden den zweiten oder dritten Operanden zurückgibt.
<code>
Syntax: Logical-OR-expression ? expression : condition-expression
</code>
Entspricht der if()-Anweisung, wobei der ? Operator als solches einen Wert zurückgibt! Expression wird nur ausgewertet, wenn der erste Operand true ist. Andernfalls wird nur condition-expression ausgeführt. Der zurückgegebene Datentyp ergibt sich aus der Expression resp. Condition-expression. Beide sollten somit vom identischen Datentyp sein.
Folgendes gilt es bei der Nutzung des ?-Operators zu beachten
* Der Datentyp Expression und condition-Expression muss identisch sein
<syntaxhighlight lang="C">
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=5;
a=a > 10 ? "String" : 4; //KO, "String" ist vom Datentyp (char*) und
// 4 ist vom Datentyp (int).
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Nach der GNU-C Reference kann der mittlere Operand fehlen, in diesem Fall wird stattdessen das Ergebnis des linken Operanden dort eingesetzt (siehe https://gcc.gnu.org/onlinedocs/gcc/Conditionals.html#Conditionals)
<syntaxhighlight lang="C">
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=13;
int b=a>10 ? : 0; //wenn a > 10 wird true, andernfalls false zurückgegeben
printf("b=%d\n",b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Sollen innerhalb von condition-expression mehrere (durch Komma getrennte) Anweisungen enthalten sein, so sind diese zu Klammern! Andernfalls bedingt die niedrige Priorität des Komma-Operators ein anders Verhalten, als erwartet.
<syntaxhighlight lang="C">
int a=7,max=5;
max=a>max ? a : max; //Alles bestens
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int a=7;
int max=5;
max=a>max ? a : max; //Alles bestens
printf("max=%d\n",max);
int var0,var1,var2;
var0=a>5 ? a++,5:6,a=1; //das zweite Komma wird als separate Anweisung
//ausgeführt und kommt somit immer zur
//Ausführung
printf("var0=%d a=%d\n",var0,a);
var1=(a>5 ? a++,5:6),a=1; //durch Klammerung klare Abgrenzung
printf("var1=%d a=%d\n",var1,a);
var2= a>5 ? a++,5 : (6,a=1); //durch Klammerung klare Abgrenzung
printf("var2=%d a=%d\n",var2,a);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die Nutzung des ?-Operators empfiehlt sich an diversen Stellen:
* Bei Makros
:<syntaxhighlight lang="C">
#define MAX(a,b) (a>b?a:b)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#define MAX(a,b) (a>b?a:b)
int main(int argc, char *argv[]) {
printf("MAX(4,5)=%d\n",MAX(4,5));
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Beim Fehlerhandling
:<syntaxhighlight lang="C">
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str=strstr("hallo123","lox");
//Ausgabe von str nur, wenn Suche erfolgreich (str!=NULL) war
printf("%s",str!=NULL?str : "(not found)" );
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion ausgeführt wird
<syntaxhighlight lang="C">
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn ret==0 ist
//andernfalls wird ret zurückgegeben
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 0;
}
int init2(void) {
printf("init2() called\n");
return 0;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //im Fehlerfreien gibt init1() 0 zurück
ret=ret?:init2(); //Aufruf von init2() nur wenn Ret==0 ist
//andernfalls wird Ret zurückgegeben
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Logische Verknüpfungen ===
Alle logischen Operationen nutzen als Operanden Ganzzahlen ,Gleitkommazahlen oder Zeiger. Der Operand wird als false angesehen, wenn der Operand 0, 0.0 oder NULL ist. Andernfalls als true. Das Ergebnis ist immer vom Datentyp int und hat den Wert von 0 oder 1.
<code>Syntax: Expression && Expression</code><br />
<code>Syntax: Expression || Expression</code><br />
<code>Syntax: ! Expression</code><br/>
Bei der logischen UND und ODER Verknüpfung wird zuerst der linke Ausdruck ausgewertet (Operator ist ein Sequence Point). Der rechte Ausdruck wird nur ausgeführt, wenn:
* bei der logischen UND Verknüpfung der linke Ausdruck TRUE ergab
* bei der logische OR Verknüpfung der linke Ausdruck FALSE ergab
Andernfalls steht das Ergebnis schon mit der Auswertung des linken Operanden fest.<br />
In der theoretischen Informatik wird dies 'Non-strict-evaluation' genannt, bei welcher der Rückgabewert feststeht, bevor alle Ausdrücke bearbeitet worden sind.
Beispiel für das Verhalten des Ausbleibens der Auswertung des zweiten Operators:
<syntaxhighlight lang="C">
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a || ++a)
b=1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0,b=0;
//a=-1; //Als alternativer Startwert
if(++a {{!}}{{!}} ++a)
b=1;
printf("a=%d b=%d\n",a,b);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Diese Funktionalität ist insbesondere beim Umgang mit Fehlern vorteilhaft:
* Prüfen, ob eine Variable einen gültigen Wert hat, bevor sie weiterverwendet wird
<syntaxhighlight lang="C">
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *str = strstr("hallo123","la");
if(str!=NULL && strlen(str) )
printf("Len = %ld",strlen(str));
else
printf("Kein Substring im String gefunden\n");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Prüfen, ob eine Funktion erfolgreich ausgeführt wurde, bevor eine weitere Funktion aufgerufen wird:
<syntaxhighlight lang="C">
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int init1(void) {
printf("init1() called\n");
return 1;
}
int init2(void) {
printf("init1() called\n");
return 1;
}
int main(int argc, char *argv[]) {
int ret;
ret=init1(); //Bei erfolgreicher Initialisierung wird 1 zurückgegeben
ret=ret && init2();
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Bitweise Verknüpfungen ===
Alle bitweisen Operationen nutzen als Operanden Ganzzahlen. Bei vorzeichenbehafteten Zahlen ist das Ergebnis nach [C11 6.5] Implementierungsabhängig, wobei das Vorzeichenbit zumeist als eigenständiges Bit angesehen wird und bei UND/ODER/EXOR als normales BIT betrachtet wird.
<code>Syntax: Ganzzahl & Ganzzahl → Bitweise UND Operation</code><br />
<code>Syntax: Ganzzahl | Ganzzahl → Bitweise ODER Operation</code><br />
<code>Syntax: Ganzzahl ^ Ganzzahl → Bitweise EXOR Operation</code><br />
<code>Syntax: ~ Ganzzahl → Bitweise Negierung</code><br />
<code>Syntax: Ganzzahl >> additive-expression</code><br />
<code>Syntax: Ganzzahl << additive-expression</code><br />
Mittels des Schiebeoperators können Ganzzahlen um additive-expression bitweise nach Links <code><<</code> oder Rechts <code>>></code> verschoben werden. Der resultierende Datentyp ergibt sich aus dem linken Operanden. Der rechte Operand muss positiv und kleiner gleich der Bitbreite des linken Operanden sein. Andernfalls ist das Ergebnis implementierungsspezifisch.
Nach [C11 6.5.7] ist das Ergebnis der Schiebeoperation implementierungsspezifisch, wenn der linke Operand eine negative vorzeichenbehaftete Zahl ist. In der Regel wendet der Compiler jedoch folgende Schiebeoperation an:
* Logisches Schieben (zu füllende Bit-Stellen werden mit 0 aufgefüllt), wenn der linke Operand eine vorzeichenlose Zahl ist
* Arithmetisches Schieben (zu füllende Bit-Stelle beim Rechtsschieben wird mit dem Vorzeichenbit aufgefüllt), wenn der linke Operand eine vorzeichenbehaftete Zahl ist. Hiermit wird das Vorzeichen beibehalten, so dass eine negative Zahl nach dem Schieben weiterhin negativ ist (In Java erfolgt dies durch den >>> - Operator)
Hinweis:
* Ein Schieben um eine Stelle nach rechts entspricht einer Division durch 2
* Ein Schieben um eine Stelle nach links entspricht einer Multiplikation mit 2
=== sizeof-Operator ===
Der sizeof-Operator dient zur Ermittlung des Speicherbedarfs (in Bytes) einer Variablen/eines Datentyps.
<code>Syntax: sizeof (type-name)</code><br />
<code>Syntax: sizeof unary-expression</code><br />
Als Argument für den Sizeof-Operator kann wahlweise ein Datentyp, eine Variable oder ein Ausdruck genutzt werden. Sizeof gilt als Konstantenausdruck, d.h. seine Berechnung erfolgt durch den Compiler, sodass:
* sizeof zur Initialisierung von globalen Variablen genutzt werden
:<syntaxhighlight lang="C">
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
struct xyz{int x,y,z;};
size_t size=sizeof(struct xyz); //3*sizeof(int)=12
int main(int argc, char *argv[]) {
printf("size=%zu\n",size);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* bei einem Ausdruck dieser nicht ausgeführt wird, sondern nur der resultierende Datentyp bestimmt wird und dessen Größe zurückgegeben
:<syntaxhighlight lang="C">
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
short var=4711;
size_t size=sizeof var++; //var=4711, size=2
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Der resultierende Datentyp des Rückgabewertes ist size_t.
Es empfiehlt sich, den sizeof-Operator mit Klammern zu nutzen, andernfalls wird im Falle eines Ausdruckes der Speicherbedarf des linken Operanden angegeben:
<syntaxhighlight lang="C">
size_t size;
short var;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
size_t size;
short var=0;
size=sizeof var+0; //size=2, da sizeof auf var angewendet wird
printf("size=%zu var=%d\n",size,var);
size=sizeof(var+0); //size=4, da sizoeof auf den resultierenden datentyp
//angewendet wird
printf("size=%zu var=%d\n",size,var);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweise:
* sizeof angewendet auf char gibt immer den Wert 1 zurück.
* sizeof ist nicht auf Operanden vom Typ Funktion, void, Felder ohne Größenangabe und Bitfelder anwendbar
* wird sizeof auf ein VLA angewendet, so entspricht sizeof nicht mehr einen Konstantenausdruck, sondern einem Funktionsaufruf
:<syntaxhighlight lang="C">
void foo(int n) {
int arr[n];
size_t size=sizeof(arr); //Speicherbedarf ist kein Konstantenausdruck
//sondern wird zur Laufzeit berechnet
</syntaxhighlight>
* Sizeof entspricht nicht strlen(), da sizeof den für die Variable reservierten Speicherbereich zurückgibt und nicht wie strlen() den Inhalt des Speicher hinsichtlich des Stringendezeichens auswertet.
:<syntaxhighlight lang="C">
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char string[100]="Test";
printf("%zu\n",sizeof(string)); //100
printf("%zu\n",strlen(string)); //4
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Anweisungen ==
=== If-Anweisung ===
<code>Syntax: if (expression) statement</code><br />
<code>Syntax: if (expression) statement else statement</code><br />
Das Ergebnis des Ausdruckes (Ganzzahl, Gleitkommazahl oder Zeiger) wird auf ungleich 0, 0.0 oder NULL getestet. Trifft dies zu, so wird statement ausgeführt. Andernfalls wird das else statement ausgeführt, sofern vorhanden. Sollen mehrere Anweisungen ausgeführt werden, so sind diese mittels Block zusammenzufassen (diesen dann bitte nicht mit ; abschließen).
Beispiel:
<syntaxhighlight lang="C">
if(a==1)
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
if(a) //entspricht a!=0
if(printf("hallo")<0) //prüfen, ob printf() fehlschlägt
if( ({int dummy=a;a=b;b=dummy;})==6)
if(a=7) //Zuweisung!
if(7=a) //KO, Eine Konstante kann kein L-Value sein
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1,b=2;
if(a==1)
printf("a==1\n");
if(a=1) //Erst Zuweisung, dann prüfen der Rückgabe der Zuweisung
printf("a=1\n");
if(a) //entspricht a!=0
printf("a\n");
if(printf("hallo\n")<0) //prüfen, ob printf() fehlschlägt
printf("printf()\n");
if( ({int dummy=a;a=b;b=dummy;})==6)
printf("({...})\n");
if(a=7) //Zuweisung!
printf("a=7\n");
if(7=a) //KO, Eine Konstante kann kein L-Value sein
;
if(7==a)
{printf("a ist 7");}; //Semikolon hinter Blocksope ist eine zweite
else //Anweisung, so dass die ELSE Anweisung nicht
{printf("Compilerfehler");};//zur IF-Anwesigung zugeordnet werden kann.
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Bei der Anweisung <code>if(a==7)</code> finden aus syntaktischer Sicht zwei Aktionen statt. Zunächst wird geprüft, ob a gleich 7 ist. Dieser Vergleich liefert true(=1) oder false(=0) zurück. Die If-Anweisung prüft im Anschluss, ob das Argument true oder false ist.
=== For-Anweisung ===
<code>Syntax: for(Initialisierungsteil<sub>OPT</sub> ; Test<sub>OPT</sub> ; Fortsetzung<sub>OPT</sub>) Statement</code>
Die For-Anweisung wird vom Compiler wie folgt umgesetzt:
<poem> '''Initialisierungsteil'''<sub>OPT</sub>
Goto Next
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
'''Statement'''
Continue:
'''Fortsetzung'''<sub>OPT</sub>
Next:
if('''Test'''<sub>OPT</sub>) goto Goon
Break:
</poem>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
for(summe=lauf=0;lauf<20;lauf++)
summe+=lauf;
printf("summe=%d\n",summe);
//Initialisierungsteil
summe=lauf=0;
goto Next;
Goon:
//Continue-Anweisung entspricht goto Continue
//Break-Anweisung entspricht goto Break;
//Statement
summe+=lauf;
Continue: __attribute__((unused))
//Fortsetzung
lauf++;
Next:
//if(TestOPT) goto Goon
if(lauf<20) goto Goon;
Break: __attribute__((unused))
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Die einzelne Elemente haben folgende Bedeutung/Besonderheiten:
;Initialisierungsteil: Zum Initialisieren von Schleifenvariablen, wird einmalig mit Beginn der FOR-Anweisung ausgeführt.
:* kann Leer sein, dann erfolgt keine Initialisierung
:* Ab C99: Hier kann eine lokale Variable definiert werden, welche nur innerhalb dieser For-Anweisung gültig ist
;Testteil: Hierin wird vor jedem Schleifendurchlauf geprüft, ob die Schleifenbedingung erfüllt ist. Wenn Bedingung nicht erfüllt ist (Ganzzahl, Gleitkommazahl oder Zeiger gleich 0,0.0 oder NULL), wird die For-Schleife beendet.
:* Kann leer sein, dann wird dieser Teil als true angesehen
;Fortsetzungsteil: Wird nach jeden Schleifendurchlauf ausgeführt. In der Regel sollte hier die Schleifenvariable aktualisiert werden
:* Kann leer sein
;Statement: In der Schleife auszuführender Ausdruck
:* Sollen mehrere Ausdrücke ausgeführt werden, so sind diese in einem Block zusammen zu fassen.
:Ergänzende Anweisungen innerhalb des Statements/Block
:* 'continue' zum Fortsetzen des Schleifendurchlaufes, d.h. Sprung zum Fortsetzungs-Teil
:* 'break', zum Beenden des Schleifendurchlaufes
Beispiele:
* For-Schleife mit lokaler Schleifenvariable
:<syntaxhighlight lang="C">
char string[]="hallo";
for(size_t lauf=0; lauf < strlen(string); lauf++)
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
//Schleife ist Suboptimal, da in jedem Durchlauf die Funktion
//strlen() aufgerufen wird!
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife mit Break-Anweisung
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t lauf=0; src[lauf]!=0; lauf++) {
printf("lauf=%zu\n",lauf);
if(lauf >= sizeof(dest))
break;
dest[lauf]=src[lauf];
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleife, bei welcher die gesamte Aktion innerhalb der For-Anweisung ausgeführt wird
:<syntaxhighlight lang="C">
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;
src[l]!=0 && l <sizeof(dest);
printf("l=%zu\n",l),dest[l]=src[l],l++);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char dest[5];
char src[10]="HalloWelt";
for(size_t l=0;src[l]!=0 && l <sizeof(dest); printf("l=%zu\n",l),dest[l]=src[l],l++);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Schleifenvariable muss keine Zählvariable sein
:<syntaxhighlight lang="C">
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int zahl=0b100010;
int bits=0;
for(int mask=0b10000000; mask!=0; mask>>=1 )
bits+= zahl & mask ? 1 : 0;
printf("Anzahl Einsen in %b = %d\n",zahl,bits);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zeiger als Schleifenvariable
:<syntaxhighlight lang="C">
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char src[]="hallo";
char dst[strlen(src)+1];
char *s,*d;
for(s=src,d=dst; *s; )
*d++=*s++;
*d=0;
printf("src='%s' dst='%s'\n",src,dst);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Zur Geschwindigkeitsoptimierung sollten im Test- und Fortsetzungsteil keine Funktionsaufrufe mit Werten enthalten sein, die sich innerhalb der Schleife nicht ändern:
:<syntaxhighlight lang="C">
for(size_t lauf=0;lauf<strlen("hallo");lauf++)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(size_t lauf=0; lauf < strlen(string1); lauf++)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
size_t count2=strlen(string2);
for(size_t lauf=0; lauf < count2; lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Zur Geschwindigkeitssteigerung sollte im Testteil auf 0 abgefragt werden, d.h. die Schleifenvariable dekrementiert werden
:<syntaxhighlight lang="C">
for(int lauf=700000;lauf;lauf--)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <time.h>
struct timespec diff_timespec(const struct timespec *minuend,
const struct timespec *subtrahend ) {
struct timespec diff = {
.tv_sec = minuend->tv_sec - subtrahend->tv_sec,
.tv_nsec = minuend->tv_nsec - subtrahend->tv_nsec};
//Sekundenüberlauf?
if (diff.tv_nsec < 0) {
diff.tv_nsec += 1000000000;
diff.tv_sec--;
}
return diff;
}
int main(int argc, char *argv[]) {
char string1[10000];
char string2[10000];
memset(string1,'a',sizeof(string1));
memset(string2,'a',sizeof(string2));
string1[sizeof(string1)-1]=0;
string2[sizeof(string2)-1]=0;
struct timespec start1,stop1;
struct timespec start2,stop2;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start1);
size_t sum1=0;
for(ssize_t lauf=700000000;lauf;lauf--)
sum1++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop1);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&start2);
size_t sum2=0;
for(ssize_t lauf=0;lauf<700000000;lauf++)
sum2++;
clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&stop2);
stop1=diff_timespec(&stop1,&start1);
stop2=diff_timespec(&stop2,&start2);
printf("Slow: Sum1=%zu Time=%lds %ldns\n",sum1,stop1.tv_sec,stop1.tv_nsec);
printf("Fast: Sum2=%zu Time=%lds %ldns\n",sum2,stop2.tv_sec,stop2.tv_nsec);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Alternativ zu einer Laufvariablen empfiehlt sich die Nutzung von Pointer als Schleifenvariable;
:<syntaxhighlight lang="C">
for(char *ptr=str; *ptr; ptr++);
</syntaxhighlight>
=== While-Anweisung ===
<code>Syntax: while(expression) Statement </code><br />
<code>Syntax: do Statement while(expression);</code><br />
Die While-Anweisungen werden vom Compiler wie folgt umgesetzt:
{| class="wikitable"
! while()-Anweisung !! do while()-Anweisung
|-
| <poem>
Continue:
if(!'''expression''')
goto Break
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
'''Statement'''
goto Continue
Break:
</poem> ||
<poem>
GoOn:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
'''Statement'''
Continue:
if('''expression''')
goto GoOn
Break:
</poem>
|}
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=
#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf;
int summe;
lauf=summe=0;
while(lauf<10) {
if(lauf>=5)
break;
lauf++;
if(lauf<3)
continue;
summe+=lauf;
}
printf("summe=%d\n",summe);
lauf=summe=0;
Continue1:
if(!(lauf<10))
goto Break1;
//Break-Anweisung entspricht
// goto Break;
//Continue-Anweisung entspr.
// goto Continue;
//Statement
if(lauf>=5) {
goto Break1;
}
lauf++;
if(lauf<3)
goto Continue1;
summe+=lauf;
goto Continue1;
Break1:
printf("summe=%d\n",summe);
lauf=summe=0;
do {
lauf++;
if(lauf>5)
break;
if(lauf<3)
continue;
summe+=lauf;
} while(lauf<10);
printf("summe=%d\n",summe);
lauf=summe=0;
GoOn2:
//Break-Anweisung entspr.
// goto Break
//Continue-Anweisung ent.
// goto Continue
//Statement
lauf++;
if(lauf>5)
goto Break2;
if(lauf<3)
goto Continue2;
summe+=lauf;
Continue2:
if(lauf<10)
goto GoOn2;
Break2: __attribute__((unused));
printf("summe=%d\n",summe);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Folgendes gilt es bei der Nutzung der While-Anweisung zu beachten:
* Soll mehr als ein Statement innerhalb der While-Schleife ausgeführt werden, so sind diese in einem Block zu schreiben
* Statement kann eine Leeranweisung (gekennzeichnet durch ein Semikolon) sein
:<syntaxhighlight lang="C">
while(1);
do ; while(1);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int lauf1=1000;
while(lauf1--);
int lauf2=1000;
do ; while(lauf2--);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Bei der do-While-Schleife ist das abschließende Semikolon Bestandteil des Befehls
* expression muss eine Ganzzahl, Gleitkommazahl oder Zeiger zurückgeben, der bei False (0, 0.0 oder NULL) die Schleife beendet.
Beispiele:
* Endlosschleife
:<syntaxhighlight lang="C">
while(1) {}
</syntaxhighlight>
* Schleife zum Durchlaufen eines String
:<syntaxhighlight lang="C">
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char str[]="string";
char *ptr=str;
while(*ptr++);
size_t len=ptr-str-1;
printf("Stringlänge=%zu\n",len);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
=== Switch-Anweisung ===
<code>Syntax: switch(expression) statement</code><br />
<code>Syntax: statement:= case constant-expression: statement<sub>opt</sub> default: statement<sub>opt</sub></code><br />
Die Switch-Anweisung entspricht einer verschachtelten If-Anweisung, mit der Besonderheit, dass der auszuführende Code nicht im If-Zweig stattfindet, sondern dort ein goto zum eigentlichen Code enthalten ist:
{| class="wikitable"
! Switch-Anweisung !! Compilerumsetzung
|-
|<syntaxhighlight lang="C">
switch(a) {
case 1:
int a=7;
//Code
break;
case 2:
printf("%d",a);
case 3: {
int a;
//Code
}
case 4 ... 8:
default:
//Code
}
</syntaxhighlight>
||<poem>
if(a==1)
goto label1;
else if(a==2)
goto label2;
else
goto label_default;
//-------------------
label1:
//Code
goto label_break;
label2:
//Code
label_default:
goto label_break;
label_break:
</poem>
|}
Folgendes gilt es bei der Nutzung der Switch-Anweisung zu beachten:
* <code>Expression</code> muss zu einer Ganzzahl (int, short, char, long, long long) oder enum (entspricht einer Ganzzahl) ausgewertet werden
* <code>constant-expression</code> muss eine Ganzzahl-Konstante oder ein Enumelement sein. Sie darf nicht doppelt im Block vorkommen. Der genaue Datentyp ergibt sich aus dem Datentyp der <code>expression</code>
* Lt. Spezifikation ist ein nur <code>statement</code> hinter der switch-Anweisung erlaubt, so dass nur ein <code>case</code> Fall oder der <code>default</code> Fall bedient werden kann::<syntaxhighlight lang="C">
int var=1;
switch(var) case 1: printf("hallo");
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) case 1: printf("hallo");
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Die geschweifte Klammer der <code>switch</code>-Anweisung erzeugt einen Block, so dass a) hier mehrere <code>case</code>-Fälle und b) hierin definierte Variablen innerhalb des gesamten Blocks zur Verfügung stehen (sind somit nicht <code>case</code> abhängig). Die <code>case</code> Anweisung ist nichts anderes als eine Sprungmarken (welche durch die switch-Anweisung angesprungen wird) so dass der Initialisierungsteil der lokalen Variablen übersprungen / nicht ausgeführt werden kann:
:<syntaxhighlight lang="C">
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("%d %d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
break;
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=1;
switch(a) {
int a=3; //Variable in gesamten Block gültig
case 1:
int b=3; //Variabe in gesamten Block gültig
printf("a=%d b=%d",a,b); //a undefiniert, b=3
break;
case 2:
printf("%d %d",a,b); //a und b undefiniert
break;
case 3: { //Block, so dass Variable
int a=4711; //nur in diesem CASE gültig ist
(void)a;
break;
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* GNU-C (siehe [https://www.gnu.org/software/c-intro-and-ref/manual/html_node/switch-Statement.html Switch-Statement]) erlaubt ergänzend zur Angabe einer Konstante die Angabe eines Wertebereiches:
:<syntaxhighlight lang="C">
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=2;
switch(a) {
case 1 ... 8: //Leerzeichen zwischen den Konstanten zwingend notwendig
//andernfalls wird der Punkt zur Konstante zugehörig
//interpretiert (erzeugt dann eine Gleitpunktkonstante)
printf("a im Bereich von 1 bis 8\n");
break;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* <code>break</code> ist optional. Mittels <code>break</code> wird an das Ende der Switch-Anweisung gesprungen. Wenn <code>break</code> weggelassen wird, wird die nachfolgende Anweisungen ausgeführt. Ggf. gibt der Compiler eine Warning aus. Mittels der GCC-Compiler-Anweisung __attribute__((fallthrough)); kann diese Warning unterdrückt werden:
:<syntaxhighlight lang="C">
switch(a) {
case 0: //ggf. Compiler-Warning
__attribute__((fallthrough)); case 1:
case 2:
break;
}
</syntaxhighlight>
* Ein Variable Length Array ist als Variable im Switch-Block direkt nicht erlaubt. Ist dies notwendig, so ist das VLA in einem inneren Block zu kapseln:
:<syntaxhighlight lang="C">
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
case 1:
int arr[var]; //KO
break;
case 2: {
int arr[var]; //OK
}
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Case - Anweisungen sind nichts anderes als Sprungmarken (Labels), so dass CASE-Anweisungen überall innerhalb des Switch-Blockes stehen können:
:<syntaxhighlight lang="C">
int prime(int value) {return value+1;}
void hallo(int var) {
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int prime(int value) {
return value+1;
}
int main(int argc, char *argv[]) {
int var=1;
switch(var) {
default:
if(prime(var))
case 2: case 4:
printf("%d",var);
else {
case 3: case 6:
printf("%x",var);
}
case 7:
printf("xyz");
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:oder anderen Anweisungen innerhalb des Switch-Blockes enthalten sein können:
:<syntaxhighlight lang="C">
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++;
case 7: *dst = *src++;
case 6: *dst = *src++;
case 5: *dst = *src++;
case 4: *dst = *src++;
case 3: *dst = *src++;
case 2: *dst = *src++;
case 1: *dst = *src++;
}while(--n>0);
}
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h> //fuer uintptr_t
void send(register char *dst,
register char *src,
register size_t count)
{
register char unsigned n=(count+7)/8;
switch(count%8) {
case 0: do{ *dst = *src++; printf("%02hhx ",*dst);
case 7: *dst = *src++; printf("%02hhx ",*dst);
case 6: *dst = *src++; printf("%02hhx ",*dst);
case 5: *dst = *src++; printf("%02hhx ",*dst);
case 4: *dst = *src++; printf("%02hhx ",*dst);
case 3: *dst = *src++; printf("%02hhx ",*dst);
case 2: *dst = *src++; printf("%02hhx ",*dst);
case 1: *dst = *src++; printf("%02hhx ",*dst);
}while(--n>0);
}
}
int main(int argc, char *argv[])
{
char src[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
char dst;
send(&dst,src,20);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* Eine Switch-Case Anweisung über Strings sind in C/C++ nicht möglich:
:<syntaxhighlight lang="C">
switch(str) {
case "hallo":
return 1;
case "du da":
return 2;
case "xyz":
return 3;
default:
rReturn -1;
}
</syntaxhighlight>
:Ein direkte Lösungsansatz ist die Nutzung von strcmp() zum Vergleichen von String. Da strcmp zeichenweise den String vergleicht, ist dieser Ansatz langsam. Alternativ bietet sich an, von allen String einen Hash-Wert zu berechnen und zunächst diesen Hash-Wert zu kontrollieren. Da der Hash-Wert nicht eindeutig ist, muss ergänzend ein strcmp() erfolgen:
:<syntaxhighlight lang="C">
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
#include <stdint.h>
//Lösungsansatz von: https://stackoverflow.com/questions/2826559/compile-time-preprocessor-hashing-of-string
#define H1(s,i,x) (x*65599u+(uint8_t)s[(i)<strlen(s)?strlen(s)-1-(i):strlen(s)])
#define H4(s,i,x) H1(s,i,H1(s,i+1,H1(s,i+2,H1(s,i+3,x))))
#define H16(s,i,x) H4(s,i,H4(s,i+4,H4(s,i+8,H4(s,i+12,x))))
#define H64(s,i,x) H16(s,i,H16(s,i+16,H16(s,i+32,H16(s,i+48,x))))
#define H256(s,i,x) H64(s,i,H64(s,i+64,H64(s,i+128,H64(s,i+192,x))))
#define HASH(s) ((uint32_t)(H256(s,0,0)^(H256(s,0,0)>>16)))
#define HASH_LAUFZEIT(s) (H256(s,0,0))
//Eigener Lösungsatz zur Umsetzung des vorherigen HASH-Algorithmus
//so dass dieser zur Compilezeit berechnet werden kann
//Was fehlt ist die abschließende EXOR berechnung!
//Problem war, dass die Array-Dereferenzierung nicht zur Compilezeit
//aufelöst werden kann
#define HH0(a,x) (x*65599u+a)
#define HH1(a) HH0(a,HH0(0,HH0(0,HH0(0,0))))
#define HH2(a,b) HH0(b,HH0(a,HH0(0,HH0(0,0))))
#define HH3(a,b,c) HH0(c,HH0(b,HH0(a,HH0(0,0))))
#define HH4(a,b,c,d) HH0(d,HH0(c,HH0(b,HH0(a,0))))
#define HH4x(a,b,c,d,x) HH0(d,HH0(c,HH0(b,HH0(a,x))))
#define HH5(a,b,c,d,e) HH4x(b,c,d,e,HH4x(0,0,0,a,0))
#define HH6(a,b,c,d,e,f) HH4x(c,d,e,f,HH4x(0,0,a,b,0))
#define HH7(a,b,c,d,e,f,g) HH4x(d,e,f,g,HH4x(0,a,b,c,0))
#define HH8(a,b,c,d,e,f,g,h) HH4x(e,f,g,h,HH4x(a,b,c,d,0))
#define HH9(a,b,c,d,e,f,g,h,i) HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0)))
#define HH10(a,b,c,d,e,f,g,h,i,j) HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0)))
#define HH11(a,b,c,d,e,f,g,h,i,j,k) HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0)))
#define HH12(a,b,c,d,e,f,g,h,i,j,k,l) HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0)))
#define HH13(a,b,c,d,e,f,g,h,i,j,k,l,m) HH4x(j,k,l,m,HH4x(f,g,h,i,HH4x(b,c,d,e,HH4x(0,0,0,a,0))))
#define HH14(a,b,c,d,e,f,g,h,i,j,k,l,m,n) HH4x(k,l,m,n,HH4x(g,h,i,j,HH4x(c,d,e,f,HH4x(0,0,a,b,0))))
#define HH15(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) HH4x(l,m,n,o,HH4x(h,i,j,k,HH4x(d,e,f,g,HH4x(0,a,b,c,0))))
#define HH16(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) HH4x(m,n,o,p,HH4x(i,j,k,l,HH4x(e,f,g,h,HH4x(a,b,c,d,0))))
#define EIGHTEENTH_ARGUMENT(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, \
a11,a12,a13,a14,a15,a16,a17,a18, ...) a18
#define CONCAT(c,d) c ## d
#define CONCATI(a,b) CONCAT(a,b)
#define HASH_COMPILEZEIT(...) CONCATI(HH , EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0))(__VA_ARGS__)
//Lösungsansatz basierend auf: https://renenyffenegger.ch/notes/development/languages/C-C-plus-plus/preprocessor/macros/__VA_ARGS__/count-arguments
#define COUNT_ARGUMENTS(...) EIGHTEENTH_ARGUMENT(dummy, ## __VA_ARGS__, \
16,15,14,13,12,11,10,9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
int main(int argc, char *argv[]) {
char *str="hallo";
switch(HASH_LAUFZEIT(str)) {
case HASH_COMPILEZEIT('d','u'):
if(!strcmp(str,"du"))
printf("Case \"du\":\n");
break;
case HASH_COMPILEZEIT('h','a','l','l','o'):
if(!strcmp(str,"hallo"))
printf("Case \"hallo\"\n");
else if(!strcmp(str,"xyz"))
printf("String='xyz'\n");
break;
default:
return -1;
}
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
:Siehe:[https://benhoyt.com/writings/hash-table-in-c/ Hash Table in C]
== Label + Goto ==
=== Label ===
<code>Syntax: name:</code><br />
Labels dienen zur Kennzeichnung einer Anweisung, so dass die Programmausführung an dieser Stelle fortgesetzt, resp. mit einer GOTO-Anweisung angesprungen werden kann. Ein Label ist durch den folgenden Doppelpunkt gekennzeichnet. Dem Label muss eine Anweisung folgen, welches auch eine Leeranweisung (Semikolon) sein kann.
Folgendes gilt es bei der Nutzung von Labels zu beachten:
* Ein Label entspricht der Speicheradresse des der Label-Anweisung folgenden Anweisung
* Bei nicht genutzten Labels (mit goto nicht angesprungene Labels) gibt der Compiler eine Warning aus. Diese kann beim GCC-Compiler mit __attribute__((unused)) unterdrückt werden
* die Case- und die Default-Anweisung aus der Switch-Anweisung entspricht einem Label
<br />
Labels hat eine funktionsweite Sichtbarkeit (siehe Kap [[#Gültigkeit/Sichtbarkeit von Variablen| Gültigkeit/Sichtbarkeit von Variablen]]). Dies bedeutet, dass das:
* Labels nur innerhalb einer Funktion gültig ist
* Labels einen von Variablen/Funktionen/Datentypen unabhängigen Namensraum haben
* Kein Prototyp für ein Label notwendig ist, wenn es bei Nutzung über goto noch nicht gesetzt worden ist, also nach vorne gesprungen wird
=== goto ===
<code>Syntax: goto label;</code><br />
Mit der Goto-Anweisung wird die Programmausführung an der mit <code>label</code> gekennzeichneten Stelle fortgesetzt.
Folgendes gilt es bei der Nutzung von goto zu beachten:
* Mit einer <code>goto</code> Anweisung kann an eine beliebige Steller innerhalb der '''identischen''' Funktion gesprungen werden. Es kann nicht zu einem Label in einer anderen Funktion gesprungen werden (hierzu ist <code>setjmp()</code> und <code>longjmp()</code> zu nutzen)
* Mit der Goto Anweisung kann gleichermaßen in einen Block hinein, als auch herausgesprungen werden:
:<syntaxhighlight lang="C">
goto first_time;
for(;;) {
if(a>10)
goto last_time:
first_time:
a++;
}
last_time: ;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=0;
goto first_time;
for(;;) {
printf("a=%d\n",a);
if(a>10)
goto last_time;
first_time:
a++;
}
last_time: ; //Leeranweisung wäre hier nicht nötig
return 0; //da dem Label ein return folgt!
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Wird mit der <code>goto</code> Anweisung der Initialisierungsteil einer Variablen übersprungen, so ist zwar die Variable existent, beinhaltet aber nicht ihren Initialisierungswert
Beispiel:
<syntaxhighlight lang="C">
goto label1;
if(a==3) {
label2:
printf("True\n");
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
int a=3;
goto label1;
if(a==3) {
label2:
printf("True\n");
a++;
}
else
label1:
{
printf("False\n");
}
if(a==3) goto label2;
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
Hinweis:
* In Java gibt es das Schlüsselwort goto, welches aber ohne Funktion ist. Es gibt jedoch Labels, die mit "break label" angesprungen werden können
=== Anwendungsbeispiele ===
Prinzipiell sind Goto-Anweisungen zu vermeiden. In einigen Anwendungsfällen erweist sich goto als nützlich:
* Nutzung nur einer <code>return</code> Anweisung in einer Funktionen
:<syntaxhighlight lang="C">
#include <unistd.h>
int input(int hdl,size_t buflen) {
int rc=-1;
unsigned char packettype;
if(read(hdl,&packettype,1) != 1)
goto exit;
unsigned short packetlen;
if(read(hdl,&packetlen,2) != 2)
goto exit;
if((1+packetlen) > buflen) {
rc=-2;
goto exit;
}
rc=packetlen;
exit:
return rc;
}
</syntaxhighlight>
* Konstruktor mit mehreren Initialisierungsteilen
:<syntaxhighlight lang="C">
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
}
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[]) {
enum {INIT_2,INIT_1,INIT_START} fortschritt=INIT_START;
int *ptr1;
int *ptr2;
if(!(ptr1=malloc(10)))
goto end;
fortschritt=INIT_1;
if(!(ptr2=malloc(20)))
goto end;
fortschritt=INIT_2;
// ...
end:
switch(fortschritt) {
case INIT_2: free(ptr2); __attribute__((fallthrough));
case INIT_1: free(ptr1); __attribute__((fallthrough));
case INIT_START:
}
return (int)fortschritt;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
* Abbruch einer verschachtelten Schleife
:<syntaxhighlight lang="C">
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
</syntaxhighlight>
{{noprint|
[{{:Programmieren in C/C++:Vorlage:CompilerExplorerLink|example_c=#include <stdio.h>
int main(int argc, char *argv[]) {
int arr[10][10];
size_t zeile;
size_t spalte;
for(zeile=0;zeile<10;zeile++)
for(spalte=0;spalte<0;spalte++)
if(arr[zeile][spalte]==0)
goto label_end;
label_end:
if((zeile==0) && (spalte==0))
printf("Nichts gefunden");
else
printf("Gefunden an %zu %zu",zeile,spalte);
return 0;
} | execCompilerOptions=-Wall|
execCompilerOutputShown=true
}} Öffnen im Compiler Explorer] }}
== Sonstiges ==
=== ??-Trigraphs ===
Zeichenfolge bestehend aus 3 Zeichen beginnend mit 2 Fragezeichen.
Die beiden Fragezeichen entsprechen einem ESCAPE-Operator (siehe Kap [[#Char-Konstanten|Char-Konstanten]]), welcher das nachfolgende Zeichen durch ein anderes ASCII Zeichen ersetzt. Die Ersetzung findet auch innerhalb von Strings statt.<br />
Trigraphs wurden früher genutzt, als die ALTGR Taste noch nicht üblich war.
<syntaxhighlight>
??< → { ??> → }
??( → [ ??) → ]
??/ → \ ??! → |
??' → ^ ??- → ~
??= → #
</syntaxhighlight>
Bei neuer C Varianten muss zur Nutzung von Trigraphs der Compiler mittels -trigraphs aktiviert werden.
<noinclude>
{{Navigation zurückhochvor buch
|zurücklink=Programmieren in C/C++: Toolchain/Entwicklungsumgebung
|zurücktext=Toolchain/Entwicklungsumgebung
|hochlink=Programmieren in C/C++
|hochtext=Inhaltsverzeichnis
|vorlink=Programmieren in C/C++: Datentypen
|vortext=Datentypen}}
</noinclude>
f2hlzie7kghpy595nua46x14iu8y8rl
CPRT/cef7
0
119065
1090629
1090574
2026-09-09T18:08:58Z
Pelikam
111447
/* Details Energie E */
1090629
wikitext
text/x-wiki
[[CPRT|< Energie E - CPRT]]
=== Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|}
=== Details Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,dN
+ \frac{\partial E}{\partial S}\,dS
+ \frac{\partial E}{\partial V}\,dV </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial E}{\partial N}
+ dS\,\frac{\partial E}{\partial S}
+ dV\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> d\mu(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial N} \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\left(\,dN\,\frac{\partial E}{\partial N}\right)
+ \frac{\partial}{\partial N}\left(\,dS\,\frac{\partial E}{\partial S}\right)
+ \frac{\partial}{\partial N}\left(\,dV\,\frac{\partial E}{\partial V}\right) </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\,dE \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dt(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial S} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dp(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,N
+ \frac{\partial E}{\partial S}\,S
+ \frac{\partial E}{\partial V}\,V </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial E}{\partial N}
+ S\,\frac{\partial E}{\partial S}
+ V\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (03)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial \mu}{\partial N}
+ S\,\frac{\partial \mu}{\partial S}
+ V\,\frac{\partial \mu}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (04)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial t}{\partial N}
+ S\,\frac{\partial t}{\partial S}
+ V\,\frac{\partial t}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (05)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial p}{\partial N}
+ S\,\frac{\partial p}{\partial S}
+ V\,\frac{\partial p}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> -\,N\,d\frac{\partial E}{\partial N}
- S\,d\frac{\partial E}{\partial S}
- V\,d\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|}
e0pgrnb2no8iv2a2ei92u6s0l9tb61o
1090630
1090629
2026-09-09T18:09:32Z
Pelikam
111447
/* Details Energie E */
1090630
wikitext
text/x-wiki
[[CPRT|< Energie E - CPRT]]
=== Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|}
=== Herleitungen Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,dN
+ \frac{\partial E}{\partial S}\,dS
+ \frac{\partial E}{\partial V}\,dV </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial E}{\partial N}
+ dS\,\frac{\partial E}{\partial S}
+ dV\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> d\mu(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial N} \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\left(\,dN\,\frac{\partial E}{\partial N}\right)
+ \frac{\partial}{\partial N}\left(\,dS\,\frac{\partial E}{\partial S}\right)
+ \frac{\partial}{\partial N}\left(\,dV\,\frac{\partial E}{\partial V}\right) </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\,dE \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dt(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial S} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dp(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,N
+ \frac{\partial E}{\partial S}\,S
+ \frac{\partial E}{\partial V}\,V </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial E}{\partial N}
+ S\,\frac{\partial E}{\partial S}
+ V\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (03)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial \mu}{\partial N}
+ S\,\frac{\partial \mu}{\partial S}
+ V\,\frac{\partial \mu}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (04)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial t}{\partial N}
+ S\,\frac{\partial t}{\partial S}
+ V\,\frac{\partial t}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (05)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial p}{\partial N}
+ S\,\frac{\partial p}{\partial S}
+ V\,\frac{\partial p}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> -\,N\,d\frac{\partial E}{\partial N}
- S\,d\frac{\partial E}{\partial S}
- V\,d\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|}
6ckj1fpiywrjv14xratvvax4bw3r6dx
1090631
1090630
2026-09-09T18:21:03Z
Pelikam
111447
/* Herleitungen Energie E */
1090631
wikitext
text/x-wiki
[[CPRT|< Energie E - CPRT]]
=== Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|}
=== Herleitungen Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,dN
+ \frac{\partial E}{\partial S}\,dS
+ \frac{\partial E}{\partial V}\,dV </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial E}{\partial N}
+ dS\,\frac{\partial E}{\partial S}
+ dV\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dN\,\frac{\partial}{\partial N}</math>||<math> = </math>
|| <math> \frac{\partial }{\partial N}\,dN </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> d\mu(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial N} \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\left(\,dN\,\frac{\partial E}{\partial N}\right)
+ \frac{\partial}{\partial N}\left(\,dS\,\frac{\partial E}{\partial S}\right)
+ \frac{\partial}{\partial N}\left(\,dV\,\frac{\partial E}{\partial V}\right) </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\,dE \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dt(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial S} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dp(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,N
+ \frac{\partial E}{\partial S}\,S
+ \frac{\partial E}{\partial V}\,V </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial E}{\partial N}
+ S\,\frac{\partial E}{\partial S}
+ V\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (03)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial \mu}{\partial N}
+ S\,\frac{\partial \mu}{\partial S}
+ V\,\frac{\partial \mu}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (04)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial t}{\partial N}
+ S\,\frac{\partial t}{\partial S}
+ V\,\frac{\partial t}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (05)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial p}{\partial N}
+ S\,\frac{\partial p}{\partial S}
+ V\,\frac{\partial p}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> -\,N\,d\frac{\partial E}{\partial N}
- S\,d\frac{\partial E}{\partial S}
- V\,d\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|}
hutqq9n4l973jj2zjzd56b8yqiak4nj
1090653
1090631
2026-09-10T10:18:31Z
Pelikam
111447
/* Herleitungen Energie E */
1090653
wikitext
text/x-wiki
[[CPRT|< Energie E - CPRT]]
=== Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|}
=== Herleitungen Energie E ===
{|
|-
|| <math> (01)\qquad </math>
|| <math> dE(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,dN + t\,dS + p\,d(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,dN
+ \frac{\partial E}{\partial S}\,dS
+ \frac{\partial E}{\partial V}\,dV </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial E}{\partial N}
+ dS\,\frac{\partial E}{\partial S}
+ dV\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> \frac{\partial}{\partial N}\left(dN \frac{\partial E}{\partial N}\right)</math>||<math> = </math>
|| <math> dN\frac{\partial }{\partial N}\frac{\partial E}{\partial N} </math>
|| <math> \qquad \partial_N(dN) = d(\partial_N N) = 0 \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> d\mu(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial N} \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ dS\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\left(\,dN\,\frac{\partial E}{\partial N}\right)
+ \frac{\partial}{\partial N}\left(\,dS\,\frac{\partial E}{\partial S}\right)
+ \frac{\partial}{\partial N}\left(\,dV\,\frac{\partial E}{\partial V}\right) </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial}{\partial N}\,dE \neq 0 </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dt(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial S} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> dp(N,S,V) </math>||<math> = </math>
|| <math> +\,d\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,dN\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ dS\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ dV\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} \neq 0 </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (02)\qquad </math>
|| <math> E(N,S,V) </math>||<math> = </math>
|| <math> +\,\mu\,N + t\,S + p\,(-V) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,\frac{\partial E}{\partial N}\,N
+ \frac{\partial E}{\partial S}\,S
+ \frac{\partial E}{\partial V}\,V </math>
|| <math> \qquad\qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial E}{\partial N}
+ S\,\frac{\partial E}{\partial S}
+ V\,\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (03)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial \mu}{\partial N}
+ S\,\frac{\partial \mu}{\partial S}
+ V\,\frac{\partial \mu}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial N}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial N}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial N} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (04)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial t}{\partial N}
+ S\,\frac{\partial t}{\partial S}
+ V\,\frac{\partial t}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial S}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial S}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial S} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (05)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial p}{\partial N}
+ S\,\frac{\partial p}{\partial S}
+ V\,\frac{\partial p}{\partial V} </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> +\,N\,\frac{\partial}{\partial N}\frac{\partial E}{\partial V}
+ S\,\frac{\partial}{\partial S}\frac{\partial E}{\partial V}
+ V\,\frac{\partial}{\partial V}\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|-
|| <math> (06)\qquad </math>
|| <math> 0 </math>||<math> = </math>
|| <math> -\,N\,d\mu - S\,dt - V\,d(-p) </math>
|| <math> \qquad (N,S,V) \qquad </math>
|-
|| <math> \qquad\qquad </math>
|| <math> </math>||<math> = </math>
|| <math> -\,N\,d\frac{\partial E}{\partial N}
- S\,d\frac{\partial E}{\partial S}
- V\,d\frac{\partial E}{\partial V} </math>
|| <math> \qquad\qquad </math>
|}
i6q76nks9lsqiy25z5819gd4dvdx4it
CPRT.I.A
0
121329
1090646
1090429
2026-09-10T10:08:07Z
EmausBot
79582
Bot: Korrigiere doppelte Weiterleitung von [[CPRT/4cb4]] auf [[CPRT/cef7]]
1090646
wikitext
text/x-wiki
#WEITERLEITUNG [[CPRT/cef7]]
4d3ljcugktgu1ceqiywe7xm5afa7l7e
CPRT.I.A.01
0
121332
1090647
1090430
2026-09-10T10:08:17Z
EmausBot
79582
Bot: Korrigiere doppelte Weiterleitung von [[CPRT/2dff]] auf [[CPRT/51da]]
1090647
wikitext
text/x-wiki
#WEITERLEITUNG [[CPRT/51da]]
l33m4p0vnac58bahnxr23hrcrg7xxc9
PCRT.I.B
0
121628
1090650
1070466
2026-09-10T10:08:47Z
EmausBot
79582
Bot: Korrigiere doppelte Weiterleitung von [[PCRT/I/b74c]] auf [[CPRT/6971]]
1090650
wikitext
text/x-wiki
#WEITERLEITUNG [[CPRT/6971]]
3ktzdjso7dssyow9zw6z0sjjbyb14rb
PCRT.I.B.02
0
121652
1090651
1070689
2026-09-10T10:08:57Z
EmausBot
79582
Bot: Korrigiere doppelte Weiterleitung von [[PCRT/I/ed2a]] auf [[CPRT/9cdc]]
1090651
wikitext
text/x-wiki
#WEITERLEITUNG [[CPRT/9cdc]]
hhnv5fie59ubhocn0nkeak4512pecf6
First Responder/Grundlagen
0
123026
1090638
1089549
2026-09-10T02:14:19Z
2ndoptimist
116642
initial
1090638
wikitext
text/x-wiki
== Was sind First Responder? ==
=== Aufgaben ===
First Responder sind in Erster Hilfe ausgebildete Privatpersonen, welche bei bestimmten Einsatzindikationen, beispielsweise Herz-Kreislauf-Stillstand, nebst den regulären Rettungskräften alarmiert werden. Sie erreichen in rund 85 % der Fälle, aufgrund der Nähe zum Einsatzort und Ortskenntnissen, den Einsatzort vor der Ambulanz.
First-Responder-Systeme sind immer als Ergänzung, nie aber als Konkurrenz oder gar als Ersatz für die regulären Rettungskräfte zu verstehen. Sie überbrücken durch Erstmassnahmen das therapiefreie Intervall von Notfallpatientinnen und Notfallpatienten bis zum Eintreffen der professionellen Rettungskräfte.
Es gelten kantonal oder gar regional abweichende Anforderungen und Alarmierungssysteme. Generell sind in etwa folgende Kriterien gültig:
* Gültiges BLS-AED-SRC Komplett-Zertifikat (Erneuerung alle 2 Jahre) oder Berufsdiplom
* Absolvierung der Einführungsschulung
* Mindestalter 18 Jahre
* Besitz eines Smartphones (Android / iOS) und Installation der App gemäss Vorgaben
* Verfügbarkeit für First-Responder-Einsätze
* Physische und psychische Belastbarkeit
=== Grenzen ===
Die Aufgaben und Kompetenzen richten sich nach den Kursinhalten und beschränken sich grundsätzlich auf medizinische Erstmassnahmen bei einer Reanimation (Beatmung, Herzdruckmassage und AED-Anwendung). Weitere Erste-Hilfe-Massnahmen sind erlaubt.
Werden First Responder selbst Zeugin oder Zeuge eines Ereignisses, welches eine Alarmierung der First Responder gemäss Einsatzindikationen erfordert, haben sie umgehend über die Notrufnummer 144 professionelle Hilfe zu alarmieren. Bis zum Eintreffen des Rettungsdiensts übernehmen First Responder die angezeigten Aufgaben im Rahmen ihrer Kompetenzen und Fähigkeiten.
Nach Abschluss des Einsatzes haben First Responder ein Einsatzprotokoll auszufüllen.
=== Zusammenarbeit mit Rettungsdienst ===
First Responder sind keine eigenständige Organisation oder Interventionseinheit in der sanitätsdienstlichen Versorgung, sondern eine Unterstützung des regulären Rettungsdiensts. Sobald der Rettungsdienst eintrifft, führt dieser den Einsatz. Es hat durch First Responder ein mündlicher Übergaberapport an den eingetroffenen Rettungsdienst über die angetroffene Situation und die eingeleiteten Massnahmen zu erfolgen.
First Responder unterstützen bei Bedarf und auf Anordnung den Rettungsdienst. Wenn gemäss Auskunft der Teamleiterin oder des Teamleiters des Rettungsdiensts keine weitere Unterstützung nötig ist, verlassen First Responder den Einsatzort.
=== Rechtliche Grundlagen ===
Die rechtlichen Grundlagen unterscheiden sich von Kanton zu Kanton. Geregelt sind die Mindestanforderungen, die Alarmierung, Haftungsfragen sowie die Ausrüstung und allenfalls Entschädigungen.
=== Eigenschutz ===
Zwecks Selbstschutz wird die Hepatitis-B-Impfung empfohlen. Während dem Einsatz ist auf entsprechend umsichtiges Handeln zu achten. Unmittelbare Gefahren wie Verkehr, Strom, Atemgifte Explosins- und Erstickungsgefahr etc. sind zu beachten.
Können Eindrücke wie schwere Verletzungen, Personen die bereits verstorben sind oder während der Intervention versterben oder heftige Reaktionen von Angehörigen nicht verarbeitet werden und stellen eine traumatische Belastung dar, wird den First Responder ebenfalls Unterstützung angeboten.
== Der Alarm ==
=== Alarmierung ===
Die Entscheidung und Verantwortung betreffend die Alarmierung von First Respondern obliegt der Notrufzentrale. Erhalten First Responder einen Alarm, liegt es im persönlichen Ermessen, ob der Einsatz angenommen wird. Erst wenn der Alarm angenommen wurde, besteht eine Einsatzpflicht. Wird diese nicht erfüllt, können First Responder vom System ausgeschlossen werden.
=== Vorbereitung während der Anfahrt ===
=== Erweitertes Material und Hilfsmittel ===
== Einsatzgrundsätze ==
=== Mach langsam, es eilt! ===
=== Übersicht verschaffen ===
=== Prioritäten ===
=== Eigenschutz ===
=== Patientenschutz ===
2ickgewl79toev4rqfzh35od7xgszd3
CPRT/I/4cb4
0
123091
1090649
1090346
2026-09-10T10:08:37Z
EmausBot
79582
Bot: Korrigiere doppelte Weiterleitung von [[CPRT/4cb4]] auf [[CPRT/cef7]]
1090649
wikitext
text/x-wiki
#WEITERLEITUNG [[CPRT/cef7]]
4d3ljcugktgu1ceqiywe7xm5afa7l7e
CPRT/I/2dff
0
123092
1090648
1090356
2026-09-10T10:08:27Z
EmausBot
79582
Bot: Korrigiere doppelte Weiterleitung von [[CPRT/2dff]] auf [[CPRT/51da]]
1090648
wikitext
text/x-wiki
#WEITERLEITUNG [[CPRT/51da]]
l33m4p0vnac58bahnxr23hrcrg7xxc9
Traktorenlexikon: Allis-Chalmers 7580
0
123103
1090619
2026-09-09T12:29:37Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1090619
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 4 WD-Serie
| MODELL = 7580
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Rahmenbauweise
| PRODUKTIONSBEGINN = 1976
| PRODUKTIONSENDE = 1981
| STÜCKZAHL = 1.610
| EIGENGEWICHT = 9.423
| LÄNGE = 6.477
| BREITE = 2.426
| HÖHE = 3.353
| RADSTAND = 3.200
| BODENFREIHEIT = 742
| SPURWEITE = 1.727-2.921
| SPURWEITE VORNE =
| SPURWEITE HINTEN =
| WENDERADIUS MIT LENKBREMSE = 6.110
| WENDERADIUS OHNE LENKBREMSE =
| BEREIFUNG VORNE = 23.1-30 AS
| BEREIFUNG HINTEN = 23.1-30 AS
| LEISTUNG KW = 163,3
| LEISTUNG PS = 222
| NENNDREHZAHL = 2.550
| ZYLINDER = 6
| HUBRAUM = 6.974
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Allradantrieb
| GETRIEBE = 20 V/4 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG = Knicklenker
}}
Parallel zur Einführung des ALLIS-CHALMERS 440, der auf dem STEIGER-BEARCAT basierte, entwickelte ALLIS-CHALMERS eigene Knicklenkerschlepper. Im Jahr 1976 wurde das erste Modell als ALLIS-CHALMERS 7580 vorgestellt. 73 % der Komponenten stammten von Traktoren der 7000 er-Serie. Das verwendete Aggregat stammte vom ALLIS-CHALMERS 7080, allerdings eine um 10 PS verstärkte Version. Als Triebwerk fungierte das 20/4-Gänge POWER-DIRECTOR-Getriebe mit einer Zweigang-Lastschaltung. Die Gesamthydraulikleistung der Pumpen betrug 284,0 l/min., wovon den größte Anteil die Lenkung beanspruchte. Die Kabine war vergleichbar mit den kleineren Modellen, und der Geräuschpegel lag bei 79 dB.
==Motor==
* ALLIS-CHALMERS, Typ: 3750 MARK-II, stehender, wassergekühlter Sechszylinder-Viertakt-Reihen-Dieselmotor mit Direkteinspritzverfahren, AC-DELCO-Kraftstoffpumpe, kopfgesteuerte Ventile, ROOSA-MASTER-Einspritzpumpe, siebenfach gelagerte Kurbelwelle, zahnradgetriebene Nockenwelle, Turbolader incl. Ladeluftkühlung, AC-Einspritzdüsen, Druckumlaufschmierung mittels Zahnradpumpe, Thermostarteinrichtung, Trockenluftfilter, AC-Düsenhalter, nasse-auswechselbare Zylinderlaufbuchsen, Leichtmetall-Kolben, mechanischer Fliehkraft-Verstellregler, Wasserumlaufkühlung mit Thermostat und Lamellenkühler.
* Bohrung = 107,95 mm, Hub = 127 mm
* Verdichtungsverhältnis = 16:1
* Mittlere Kolbengeschwindigkeit = 10,16 m/s
* Geregelter Drehzahlbereich = 750 bis 2.850 U/min.
* Einspritzdruck = 262 bis 265 bar
* Roosa-Master-Einspritzpumpe, Typ: DM-4
==Kupplung==
* Pedal- oder Hand-betätigte, nasse Doppel-Lamellenkupplung
* Betätigung der Fahrkupplung mittels vier Knöpfe und Handhebel-betätigtes POWER-DIRECTOR-Getriebekupplungssystem
==Getriebe==
* Im Ölbad laufendes, teilsynchronisiertes Gruppengetriebe mit Zweihebelbedienung
* Wechselgetriebe mit fünf Vorwärts- und einem Rückwärtsgang
* Gruppengetriebe mit zwei Gruppen, in die Gruppen: L und H unterteilt
* Hydraulisch-betätigtes Lastschalt-System als POWER-DIRECTOR-Gruppe bezeichnet
* Lastschaltbare Betätigung mittels Hebel ohne Kupplungseinsatz zwischen einem schnellen und einem langsamen Gang (Low/High)
20 Vorwärts- und 4 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten mit Bereifung 23.1-30 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.550
|-
! GRUPPE - L / LASTSTUFE - LO !!
|-
| 1.Gang || 2,41 km/h
|-
| 2.Gang || 4,99 km/h
|-
| 3.Gang || 6,12 km/h
|-
| 4.Gang || 6,76 km/h
|-
| 5.Gang || 8,37 km/h
|-
| 1.Rückwärtsgang || 4,51 km/h
|-
! GRUPPE - L / LASTSTUFE - HI !!
|-
| 1.Gang || 3,06 km/h
|-
| 2.Gang || 5,47 km/h
|-
| 3.Gang || 6,76 km/h
|-
| 4.Gang || 7,56 km/h
|-
| 5.Gang || 11,10 km/h
|-
| 2.Rückwärtsgang || 5,63 km/h
|-
! GRUPPE - H / LASTSTUFE - LO !!
|-
| 1.Gang || 9,33 km/h
|-
| 2.Gang || 12,55 km/h
|-
| 3.Gang || 15,29 km/h
|-
| 4.Gang || 17,06 km/h
|-
| 5.Gang || 22,85 km/h
|-
| 3.Rückwärtsgang || 10,30 km/h
|-
! GRUPPE - H / LASTSTUFE - HI !!
|-
| 1.Gang || 10,14 km/h
|-
| 2.Gang || 13,68 km/h
|-
| 3.Gang || 18,83 km/h
|-
| 4.Gang || 20,92 km/h
|-
| 5.Gang || 28,32 km/h
|-
| 4.Rückwärtsgang || 12,71 km/h
|-
|}
==Zapfwelle==
* Mechanisch-betätigte Getriebezapfwelle
* Stummel = 1 3/4"- 6 Keile
* Einfach schaltbar, 1.000 U/min.
* 996 U/min. mit Nenndrehzahl
Übertragbare Leistung = 188,9 DIN-PS
==Bremsen==
* Pedal-betätigte, nasse Mehrscheibenbremse auf die Differentialseitenwellen wirkend, als Lenkbremse ausgebildet
* Handhebel-betätigte Feststellbremse
==Achsen==
* Pendelnd-gelagerte Vorderachse
Verstellbare Spurweite = 1.727 bis 2.921 mm
* Starre Hinterachse mit Kegelradgetriebe, Tellerrad und Stirnradübersetzung
* Mechanisch-betätigte Differentialsperre
Verstellbare Spurweite = 1.727 bis 2.921 mm
* Vordere Achslast = 6.192 kg
* Hintere Achslast = 4.472 kg
==Lenkung==
* Hydrostatische Knicklenker-Lenkung
==Hydrauliksystem und Kraftheber==
* Lastabhängiger hydraulischer Kraftheber
* Dreipunktaufhängung der Kategorie III mit Schnellkuppler
Funktionen:
* Heben, Senken, Zugkraft- und Positionskontrolle
* Reaktionsregelung und Tiefeneinstellung
* Geschlossenes System mit einer Förderleistung von 87,1 l/min. bei 172 bar
Max. Hubkraft an den Koppelenden = 3.030 kg
==Steuergeräte==
* Ein bis drei einfachwirkende Steuergeräte
==Elektrische Ausrüstung==
"12-Volt Einrichtung"
* Zwei Batterien
==Maße und Abmessungen==
* Länge über alles = 6.477 mm
* Breite über alles = 2.426 bis 3.035 mm
* Höhe über Motorhaube = 2.167 mm
* Höhe über Kabine = 3.353 mm
* Radstand = 3.200 mm
* Bodenfreiheit unter der Vorderachse = 742 mm
* Betriebsgewicht = 10.664 kg
==Bereifung==
"Standardbereifung:"
* Vorne und Hinten = 23.1-30 AS
"Optional:"
* Vorne und Hinten = 18.4-38, 30.5-32, 24.5-32 und 20.8-38 AS
==Füllmengen==
* Tankinhalt = 644,0 l
* Motoröl = 18,0 bis 23,7 l
* Kühlsystem = 36,0 l
* Getriebe = 37,9 l
* Differential = 63,2 l
* Vorderachse = 56,8 l
==Verbrauch==
* Kraftstoffverbrauch = 180,3 l/h bei 188,9 DIN-PS und Nenndrehzahl
==Kabine==
* Vollverglaste Sicherheitskabine mit zwei Türen, gepolsterten Sitz, Traktormeter, Amperemeter, Kraftstoffanzeige, Heizung, Klimaanlage, Thermometer, seitliche Bedienelemente und Lade- und Öldruckanzeige
==Sonderausrüstung==
* Radgewichte
* Zusatz-Steuergeräte
* Zugpendel
* Dreipunktkupplung der KAT. III/IV mit Schnellkuppler
* Radio-Kassette
==Literatur & Weblinks==
* Allis-Chalmers Agricultural-Equipment Brochure
* tractordata.com
* digitalcommons.unl.edu (Test-Nr. 1229/76)
* koneviesti.fi
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
00zqlu9n9djpddy3yw2u4wyrddnh3au
Traktorenlexikon: Allis-Chalmers 8550
0
123104
1090623
2026-09-09T13:24:51Z
Baupit
56622
Neue Seite (vgl. [[WB:AZ]])
1090623
wikitext
text/x-wiki
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
{{:Traktorenlexikon: Modell-Infobox
| HERSTELLER = ALLIS-CHALMERS
| MODELLREIHE = 4 WD-Serie
| MODELL = 8550
| BILD =
| BILDBESCHREIBUNG =
| BAUWEISE = Rahmenbauweise
| PRODUKTIONSBEGINN = 1977
| PRODUKTIONSENDE = 1981
| STÜCKZAHL =
| EIGENGEWICHT = 11.974
| LÄNGE = 7.239
| BREITE = 2.426
| HÖHE = 3.531
| RADSTAND = 3.200
| BODENFREIHEIT = 655
| SPURWEITE = 1.651-2.921
| SPURWEITE VORNE =
| SPURWEITE HINTEN =
| WENDERADIUS MIT LENKBREMSE = 6.270
| WENDERADIUS OHNE LENKBREMSE =
| BEREIFUNG VORNE = 18.4-38 AS
| BEREIFUNG HINTEN = 18.4-38 AS
| LEISTUNG KW = 222,9
| LEISTUNG PS = 303
| NENNDREHZAHL = 2.500
| ZYLINDER = 6
| HUBRAUM = 11.972
| DREHMOMENTANSTIEG =
| KRAFTSTOFF = Diesel
| KÜHLSYSTEM = Wasserkühlung
| ANTRIEBSTYP = Allradantrieb
| GETRIEBE = 20 V/4 R
| HÖCHSTGESCHWINDIGKEIT = 30
| KATEGORIESORTIERUNG = Knicklenker
}}
Das zweite Knicklenkermodell folgte im Sommer 1977 und wurde als ALLIS-CHALMERS 8550 vorgestellt. Sein hauseigenes Sechszylinderaggregat verfügte über 12,0-Liter Hubraum und war mit zwei Turboladern und Vierventiltechnik ausgestattet. Als Triebwerk fungierte das 20/4-Gänge POWER-DIRECTOR-Getriebe mit einer Zweigang-Lastschaltung. Die Gesamthydraulikleistung der Pumpen betrug 284,0 l/min., wovon den größte Anteil die Lenkung beanspruchte. Die Kabine war vergleichbar mit den kleineren Modellen, und der Geräuschpegel lag bei 79 dB.
==Motor==
* ALLIS-CHALMERS, Typ: 6120 T, stehender, wassergekühlter Sechszylinder-Viertakt-Reihen-Dieselmotor mit Direkteinspritzverfahren, AC-DELCO-Kraftstoffpumpe, kopfgesteuerte Ventile, ROOSA-MASTER-Einspritzpumpe, siebenfach gelagerte Kurbelwelle, zahnradgetriebene Nockenwelle, zwei Turboladern, AC-Einspritzdüsen, Druckumlaufschmierung mittels Zahnradpumpe, Thermostarteinrichtung, Trockenluftfilter, AC-Düsenhalter, nasse-auswechselbare Zylinderlaufbuchsen, Leichtmetall-Kolben, mechanischer Fliehkraft-Verstellregler, Wasserumlaufkühlung mit Thermostat und Lamellenkühler.
* Bohrung = 133,35 mm, Hub = 142,88 mm
* Verdichtungsverhältnis = 16,25:1
* Mittlere Kolbengeschwindigkeit = 11,91 m/s
* Geregelter Drehzahlbereich = 800 bis 2.750 U/min.
* Einspritzdruck = 262 bis 265 bar
* Einlassventil = 0,38 mm
* Auslassventil = 0,51 mm
==Kupplung==
* Pedal- oder Hand-betätigte, nasse Doppel-Lamellenkupplung
* Betätigung der Fahrkupplung mittels vier Knöpfe und Handhebel-betätigtes POWER-DIRECTOR-Getriebekupplungssystem
==Getriebe==
* Im Ölbad laufendes, teilsynchronisiertes Gruppengetriebe mit Zweihebelbedienung
* Wechselgetriebe mit fünf Vorwärts- und einem Rückwärtsgang
* Gruppengetriebe mit zwei Gruppen, in die Gruppen: L und H unterteilt
* Hydraulisch-betätigtes Lastschalt-System als POWER-DIRECTOR-Gruppe bezeichnet
* Lastschaltbare Betätigung mittels Hebel ohne Kupplungseinsatz zwischen einem schnellen und einem langsamen Gang (Low/High)
20 Vorwärts- und 4 Rückwärtsgänge
==Geschwindigkeiten vor- und rückwärts==
"Geschwindigkeiten mit Bereifung 18.4-38 AS"
{| class="wikitable"
|-
! bei Motordrehzahl (U/min) !! 2.500
|-
! GRUPPE - L / LASTSTUFE - LO !!
|-
| 1.Gang || 3,06 km/h
|-
| 2.Gang || 4,35 km/h
|-
| 3.Gang || 5,95 km/h
|-
| 4.Gang || 7,24 km/h
|-
| 5.Gang || 8,37 km/h
|-
| 1.Rückwärtsgang || 5,96 km/h
|-
! GRUPPE - L / LASTSTUFE - HI !!
|-
| 1.Gang || 3,86 km/h
|-
| 2.Gang || 5,31 km/h
|-
| 3.Gang || 6,60 km/h
|-
| 4.Gang || 7,72 km/h
|-
| 5.Gang || 11,43 km/h
|-
| 2.Rückwärtsgang || 7,08 km/h
|-
! GRUPPE - H / LASTSTUFE - LO !!
|-
| 1.Gang || 9,33 km/h
|-
| 2.Gang || 11,59 km/h
|-
| 3.Gang || 15,77 km/h
|-
| 4.Gang || 17,54 km/h
|-
| 5.Gang || 24,94 km/h
|-
| 3.Rückwärtsgang || 15,61 km/h
|-
! GRUPPE - H / LASTSTUFE - HI !!
|-
| 1.Gang || 10,14 km/h
|-
| 2.Gang || 13,84 km/h
|-
| 3.Gang || 18,83 km/h
|-
| 4.Gang || 20,92 km/h
|-
| 5.Gang || 30,09 km/h
|-
| 4.Rückwärtsgang || 18,67 km/h
|-
|}
==Zapfwelle==
* Mechanisch-betätigte Getriebezapfwelle
* Stummel = 1 3/4"- 6 Keile
* Einfach schaltbar, 1.000 U/min.
* 998 U/min. mit Nenndrehzahl
Übertragbare Leistung = 257,4 DIN-PS
==Bremsen==
* Pedal-betätigte, nasse Mehrscheibenbremse auf die Differentialseitenwellen wirkend, als Lenkbremse ausgebildet
* Handhebel-betätigte Feststellbremse
==Achsen==
* Pendelnd-gelagerte Vorderachse
Verstellbare Spurweite = 1.651 bis 2.921 mm
* Starre Hinterachse mit Kegelradgetriebe, Tellerrad und Stirnradübersetzung
* Mechanisch-betätigte Differentialsperre
Verstellbare Spurweite = 1.651 bis 2.921 mm
* Vordere Achslast = 7.729 kg
* Hintere Achslast = 4.536 kg
==Lenkung==
* Hydrostatische Knicklenker-Lenkung
==Hydrauliksystem und Kraftheber==
* Lastabhängiger hydraulischer Kraftheber
* Dreipunktaufhängung der Kategorie III mit Schnellkuppler
Funktionen:
* Heben, Senken, Zugkraft- und Positionskontrolle
* Reaktionsregelung und Tiefeneinstellung
* Geschlossenes System mit einer Förderleistung von 87,1 l/min. bei 172 bar
Max. Hubkraft an den Koppelenden = 4.418 kg
==Steuergeräte==
* Ein bis drei einfachwirkende Steuergeräte
==Elektrische Ausrüstung==
"12-Volt Einrichtung"
* Zwei Batterien
==Maße und Abmessungen==
* Länge über alles = 7.239 mm
* Breite über alles = 2.426 bis 3.035 mm
* Höhe über Motorhaube = 2.294 mm
* Höhe über Kabine = 3.531 mm
* Höhe über Auspuff = 3.912 mm
* Radstand = 3.200 mm
* Bodenfreiheit unter der Vorderachse = 655 mm
* Betriebsgewicht = 12.265 kg
==Bereifung==
"Standardbereifung:"
* Vorne und Hinten = 18.4-38 AS
"Optional:"
* Vorne und Hinten = 20.8-34, 23.1-30, 30.5-32, 24.5-32 und 20.8-38 AS
==Füllmengen==
* Tankinhalt = 644,0 l
* Motoröl = 43,5 bis 56,8 l
* Kühlsystem = 68,0 l
* Getriebe = 37,9 l
* Differential = 63,2 l
* Vorderachse = 56,8 l
==Verbrauch==
* Kraftstoffverbrauch = 249,7 l/h bei 257,4 DIN-PS und Nenndrehzahl
==Kabine==
* Vollverglaste Sicherheitskabine mit zwei Türen, gepolsterten Sitz, Traktormeter, Amperemeter, Kraftstoffanzeige, Heizung, Klimaanlage, Thermometer, seitliche Bedienelemente und Lade- und Öldruckanzeige
==Sonderausrüstung==
* Radgewichte
* Zusatz-Steuergeräte
* Zugpendel
* Dreipunktkupplung der KAT. III/IV mit Schnellkuppler
* Radio-Kassette
==Literatur & Weblinks==
* Allis-Chalmers Agricultural-Equipment Brochure
* tractordata.com
* digitalcommons.unl.edu (Test-Nr. 1262/77)
* koneviesti.fi
<references />
{{:Traktorenlexikon: Navigation |HERSTELLER-LINK=Traktorenlexikon: Allis-Chalmers |HERSTELLER= Allis-Chalmers}}
ky53pe62fg2zuckspui2uki3euzgfst
Diskussion:Ungarisch: Thematischer Grundwortschatz: Lehnwörter/Deutsche und Lateinische Lehnwörter
1
123105
1090627
2026-09-09T17:04:03Z
T25N
97510
Neuer Abschnitt /* Windmühle */
1090627
wikitext
text/x-wiki
== Windmühle ==
malom - Mühle; molnár - Müller; szélmalom - Windmühle; Lateinisch: mola (ursprünglich der Mahlstein) [[Benutzer:T25N|T25N]] 19:04, 9. Sep. 2026 (CEST)
151vc81oflzrqsz6elgdx2onf7z90ei