Forum: Mikrocontroller und Digitale Elektronik uCs sauber programmieren in C


von C-Master (Gast)


Lesenswert?

Hallo zusammen,

bis jetzt hab ich sehr einfach Software einfach so vor mich hin 
programmiert (ohne vorher gross zu überlegen oder pläne zu zeichnen). 
Aber wie geht man vor wenn die Software etwas komplizierter wird? Gibt 
ja schnell sehr viele Fehlerquellen.

Habt ihr ein paar Tipps?

Gibt es irgendwelche Grundlegende sachen dir man beachten sollte? Viel 
if else benutzen oder wenig. Viel ineinander verschachteln oder 
möglichst wenig. Viele verschachtelungen sollte man maximal benützen?

Wann benutzt man State Machines?

Wie dokumentiert ihr Software? Immer, garnie oder im nachhinein? 
Zeichnet ihr Struktorgramme oder einfach Kommentare?

Wann verwendet man C++ bei uCs?

Und zum Schluss, habt ihr noch eine Buchempfehlung für C speziell für 
uCs?


Danke und schönen Abend

C-Master

von Thomas (Gast)


Lesenswert?

Die wichtigsten Dinge:

- Main Loop immer schön klein halten
Hier so wenig Funktionalität wie möglich unterbringen und diese hinter 
klingenden Funktionsaufrufen verbergen.

- Selbsterklärende Namen für Variablen und Funktionen wählen, ganz egal 
wie lang diese werden.

- So wenig globale Variablen wie möglich, dies sollte die absolute 
Ausnahme sein!

- Selbsterklärenden Code schreiben
Viele hier versuchen immer noch das kleinste Quäntchen an Performance 
herauszukitzeln. Dies geht oft zu Lasten der Lesbarkeit, Wartbarkeit und 
Portierbarkeit und ist (fast) nie nötig.

- Zustandsautomaten sind ein sehr gutes Stichwort
Diese Dinger sind ein Garant für guten Code, weil man von Anfang an 
gezwungen wird alles nach Lehrbuch zu machen.
Hier erstellt man zuerst das Konzept, und dann erst den Code. Das 
Konzept ist gleichzeitig die beste Doku.
Bei der Implementierung gibt es keine Fehler, da das vorher erstellte 
Zustandsdiagramm eindeutig ist. War das Konzept richtig, dann 
funktioniert das Programm auch.
Grundsätzlich sollte man sich bei jeder Aufgabe fragen, ob diese sich 
sinnvoll mit einem Automaten lösen lässt.

von Uboot- S. (uboot-stocki)


Lesenswert?

Thomas wrote:
> - So wenig globale Variablen wie möglich, dies sollte die absolute
> Ausnahme sein!
>
Wie macht Ihr es dann, wenn Ihr Zustände o.ä. in mehreren Funktionenen 
benötigt?

Ein Beispiel: Meine Rolladensteuerung - Ich benötige Uhrzeit, 
Schaltzeiten etc. in vielen Funktionen. Daher habe ich diese als globale 
Variablen implementiert. Die Alternative wäre, alle diese Werte als 
Variablen in Funktionsaufrufen zu übergeben. Dies würde m.E. aber zu 
großen Overhead bei Funktionsaufrufen führen ...

Was macht man hier? Ist es Zielführend alle mehrfach benötigten 
Variablen in ein globes Struct zu packen? Damit hätte man dann nur eine 
globale Variable ?

Also wie macht Ihrs ?

Gruß

Andreas

von Hans (Gast)


Lesenswert?

Alle nötigen Zustandsvariablen in einer Struktur zusammenfassen und dann 
einen Pointer auf diese Struktur den einzelnen Funktionen übergeben 
(=Handle auf den Kontext).

von Tomasio (Gast)


Lesenswert?

Wieso eigentlich keine globalen Variablen? Gibts da einen vernünftigen 
Grund?

von irgendjemand (Gast)


Lesenswert?

Der Globale Namensbereich ist begrenzt. Häufig hat man ja auch "status" 
Variablen, die dann mehrfach vorkommen, dann gibt es Kollisionen, also 
einfach in ne struct und die struct nach dem Modul benennen.

Auch sehr hilfreich, die sache mit dem Kontextpointer, dann kann man den 
selben Code auch mehrfach benutzen (z.B. Filteranwndungen, ...).

Meines Erachtens geht Leistung nicht gegen Lesbarkeit. Ich habe erst 
letzten Monat ein in C geschriebenes Modul (sehr gut lesbar, 100% 
portierbar), in ASM umgesetzt und nur etwa 40% eingespart. Das meisste 
natürlich beim Push/Pop (Interrupts).

Interrupts sind eh ein gutes Stichwort: ich habe gute Erfahrung gemacht, 
dieses moeglichst klein zu halten, also wenig Funktionalität dort 
reinzubringen. Wenn man dann noch ausschließlich Inline Funktionen dort 
verwendet, kommen auch brauchbar schnelle und kleine Binärdaten aus dem 
Compiler raus.

von yalu (Gast)


Lesenswert?

> Wieso eigentlich keine globalen Variablen? Gibts da einen vernünftigen
> Grund?

Der Hauptgrund ist der, dass bei globalen Variablen schwer
nachvollziehbar ist, woher sie ihre Inhalte stammen. Um das
herauszufinden, muss man den Quellcode des gesamten Programms nach
Funktionen durchscannen, die die eine bestimmte Variable beschreiben,
anschließend nachschauen, welche anderen Funktionen diese Funktionen
aufrufen usw. Problematisch wird es vor allem dann, wenn globale
Variablen an sehr vielen Stellen im Programm beschrieben werden.

Bei lokalen Variablen muss hingegen nur eine Funktion durchgelesen
werden. Selbst wenn Werte als Argumente an eine Funktion übergeben
werden, ist die Suche nach ihrem Ursprung immer noch mit begrenztem
Aufwand möglich.

Es ist aber überhaupt kein Problem, Uboot-Stockis Uhrzeitvariable
global zu machen, wenn aus Namensgebung und Dokumentation klar wird,
dass sie nur an einer Stelle, nämlich vielleicht in einem zyklisch
aufgerufenen Interrupthandler beschrieben wird. Würde man diese als
Argument über mehrere Aufrufebenen durchreichen, würde die Lesbarkeit
sogar schlechter, weil dabei nicht sofort klar wird, dass es sich bei
den Argumenten in Wirklichkeit immer um Kopien der gleichen Variable
handelt.

Es ist ebenfalls überhaupt kein Problem, eine Satz Parameter global zu
machen, wenn klar ist, dass diese einmal beim Programmstart
initialisiert (bspw. aus einem EEPROM gelesen) werden, und danach kaum
noch verändert werden. Idealerweise packt man all diese Variablen in
eine Struktur, um damit auszudrücken, dass ihre Inhalte alle aus der
gleichen Quelle stammen.

Bei der Übergabe von Werten zwischen Interrupthandlern und anderen
Programmteilen führt sowieso kein sinnvoller Weg an globalen Variablen
vorbei. Aber auch hier kann man die Lesbarkeit verbessern, wenn man
jeweils alle globalen Variablen eines Interrupthandlers zu einer
Struktur (bspw. timer_irqvars, uart_irqvars usw.) zusammenfasst.

Globale Variablen sind also nicht böse, genauso wenig wie Gotos. Man
muss sie nur mit Bedacht einsetzen.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

yalu wrote:

> Globale Variablen sind also nicht böse, genauso wenig wie Gotos. Man
> muss sie nur mit Bedacht einsetzen.

Hi yalu,
bei dem meisten was du von dir lässt nicke ich oft und gerne, wie auch 
hier bei den globalen Variablen, aber bei gotos muss ich dir 
widersprechen.
Gotos führen zu Sphagetti Code und es gibt immer eine Möglichkeit diese 
zu vermeiden.

von Winfried (Gast)


Lesenswert?

Sehe ich ähnlich, gotos habe ich in den letzten 15 Jahren Programmierung 
nicht mehr gebraucht. Ich glaub auch nicht, dass mein Programmcode 
dadurch vorteilhafter geworden wäre.

Bin aber auch ein Gegner vom blinden Befolgen irgendwelcher Regeln. Wenn 
jemand den sinnvollen Einsatz von Gotos findet, darf er die gerne 
einsetzen.

von Martin Thomas (Gast)


Lesenswert?

Die Verteufelung von goto in C ist wahrscheinlich so alt wie die 
Sprachdefintion. Sicher, man kann gotos immer irgendwie vermeiden und es 
gibt einige übergreifende oder in-house Richtlinien, die die Verwendung 
von goto auch verbieten. Aber vor allem in Funktionen mit vielen 
Verschachtelungen, bei denen z.B. sehr viele mögliche Fehlerzustände 
abgefragt werden, vermeiden machmal "mit Bedacht" eingesetzte label und 
ein paar gotos ausufernde und unübersichtliche if-else Konstrukte und 
manchmal auch die meiner Meinung nach viel fehleranfälligeren innerhalb 
einer Funktion verstreuten return fehlercodeX (mehr als ein return in 
einer Funktion wird in zumindest in zwei mir bekannten Richtlinien 
ebenfalls untersagt). Das ist dann im Prinzip ein realtiv 
übersichtliches, im Vergleich zu C++ allerdings recht primitives, 
exception-handling.

Nur meine 0,02EUR dazu; Diskussionen zu goto in C füllen wahrscheinlich 
inzwischen zehntausende von Foren-, Mailinglist-Threads und 
Internetseiten.

von Benedikt K. (benedikt)


Lesenswert?

goto ist so eine Sache. Ich kannte dies anfangs garnicht, (was 
vielleicht auch gut so war), aber mittlerweile nutze ich es ab und zu. 
Es gibt ein paar Fälle in denen es durchaus brauchbar ist:
z.B. wenn man mehrere Schleifen auf einmal verlassen möchte. OK, man 
kann es auch anderst machen indem man eine Variable setzt, die dann in 
allen Schleifen nacheinander ein break auslöst, oder gleich ein return 
um die komplette Funktion zu verlassen. Manchmal hat goto aber ein paar 
kleine Vorteile.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Mir ging es ähnlich, ich kannte goto noch aus basic, war mir aber lange 
nicht bewusst das ich damit auch in c arbeiten kann, heute bin ich froh 
das ich es nicht von anfang an kannte. Was ich häufiger sehe ist das 
gotos meistens schlechten Code unterstützen, weil man sich vorher keine 
Gedanken gemacht hat.

Ein Beispiel was mir spontan einfällt ist das Rausspringen aus 
irgendwelchen Such-Schleifen, bei einfachen Konstruktionen tut es ein 
break, bei verschachtelten Angelegenheiten packt man das Ganze einfach 
in eine Unterfunktion. Wenn man von vornerein gotos gedanklich 
ausblendet wird der Code meistens strukturierter. Im Idealfall hat man 
also dann eine Suchfunktion die als Rückgabewert einen Pointer auf die 
Gesuchte Stelle oder NULL enthält. Oder wenn nur das Enthalten eines 
Wertes in einem Feld interessiert, ist ein if (beinhaltet(Feld, x)) {}; 
auch besser lesbar als irgendwelche Sprünge.

Das schlimmste Negativ Beispiel was ich bisher gesehen hab war ein Code 
mit etwa 800 Zeilen und alles in der main, dafür aber massig gotos...
(Funktionen aus Standardheadern mal ausgenommen.)

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Erinnert mich an den alten Spruch: “Real Programmers can write
FORTRAN programs in any language.”

Sprich: man kann alles, was es gibt, immer gehörig missbrauchen (und
C setzt dem Missbrauch wenig Schranken).  Sinnvoll benutzt, ist aber
oft nichts dagegen einzuwenden.

Gerade bei sehr kleinen Controllern können globale Variablen u. U.
zu einfacherem (und kleinerem) Code führen, und eine fehlende
Übersichtlichkeit ist dort nicht das Problem, was es bei einem
Projekt auf einem Controller mit 64 und mehr KiB an Code sein kann.
Gleichermaßen bringt ein "goto", das fünf Klammerungsebenen einspart,
ggf. mehr Übersichtlichkeit in das Projekt, als man bei strikter
Meidung dieses Worts erreichen kann.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Erinnert mich an einen gewissen Finnen:
http://kerneltrap.org/node/553/2131

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Was die Globalen Variablen angeht, bastel ich auch bei Kleinstprojekten 
jeden Funktionsblock (Hauptprogramm, Timer, UART, etc.) in jeweils 
eigene C Files und binde sie bei Bedarf in andere Programme wieder ein, 
damit erledigen sich die meisten globalen Variablen von selbst.

von panam (Gast)


Lesenswert?

Für was brauchts eigentlich Pointer?? Das hab ich nie gecheckt. Man kann 
doch gleich die Variable übergeben! Bei Java wurde das doch auch 
abgeschafft.

von Karl H. (kbuchegg)


Lesenswert?

panam wrote:
> Für was brauchts eigentlich Pointer?? Das hab ich nie gecheckt. Man kann
> doch gleich die Variable übergeben!

Das ist dann aber eine Einbahnstrasse in C.
Der Wert geht zwar in die Funktion hinein, aber eine Veränderung
des Wertes in einer Funktion führt nicht zu einer Veränderung
der aufrufenden Variablen des Aufrufers.
Wenn du das so willst: super, genau das was du brauchst. Du kannst
   nach Herzenslust innerhalb der Funktion mit dem Argument
   fuhrwerken, ohne das du dem Aufrufer etwas zerstörst.
Wenn du aber haben willst, dass eine Änderung an einem Argument
   auch für den Aufrufer sichtbar ist, dann geht das in c nur,
   in dem der Aufrufer die Adresse übergibt (aka. einen Pointer)
   an der diese Änderung gemacht werden soll.

Die andere Spielwiese für Pointer sind: dynamische Datenstrukturen.
Also Arrays, Listen, Maps, Strings die zur Laufzeit bei Bedarf
anwachsen und kleiner werden können.

Pointer sind ganz einfach: Das sind Variablen, der Inhalt eine
Speicheradresse ist. So wie ein int eine ganze Zahl aufnimmt,
ein double eine Fliesskommazahl, so nimmt eine Pointer-Variable
eine Speicheradresse auf. Mehr steckt da nicht dahinter :-)

> Bei Java wurde das doch auch
> abgeschafft.

Auch in Java gibt es noch Pointer. Nur heissen sie dort AFAIK
Referenzen.

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

panam wrote:
> Für was brauchts eigentlich Pointer?? Das hab ich nie gecheckt. Man kann
> doch gleich die Variable übergeben! Bei Java wurde das doch auch
> abgeschafft.

Jein, in Java und C++ gibts Referenzen, das ist praktisch ein stark 
vereinfachter Pointer.

Wenn man einen Pointer übergibt, bleiben Änderungen an der Variablen 
erhalten da direkt der Inhalt der Speicheradresse der Variablen geändert 
wird.
Bei Variablenübergabe wird mit einer Kopie innerhalb der Funktion 
gearbeitet und nach dem rausspringen aus dieser Funktion ist diese weg.
Ausserdem kostet das Anlegen dieser Kopie Speicher und Zeit.

EDIT: Immer wieder erstaunlich wie schnell Mr. Buchegger solche 
Erklärungen aus dem Ärmel zaubert.

von Bernhard R. (barnyhh)


Lesenswert?

Das war der Original-Beitrag (nur noch mal zur Erinnerung):
------------>>
Hallo zusammen,

bis jetzt hab ich sehr einfach Software einfach so vor mich hin
programmiert (ohne vorher gross zu überlegen oder pläne zu zeichnen).
Aber wie geht man vor wenn die Software etwas komplizierter wird? Gibt
ja schnell sehr viele Fehlerquellen.

Habt ihr ein paar Tipps?

Gibt es irgendwelche Grundlegende sachen dir man beachten sollte? Viel
if else benutzen oder wenig. Viel ineinander verschachteln oder
möglichst wenig. Viele verschachtelungen sollte man maximal benützen?

Wann benutzt man State Machines?

Wie dokumentiert ihr Software? Immer, garnie oder im nachhinein?
Zeichnet ihr Struktorgramme oder einfach Kommentare?

Wann verwendet man C++ bei uCs?

Und zum Schluss, habt ihr noch eine Buchempfehlung für C speziell für
uCs?


Danke und schönen Abend

C-Master
<<------------ Ende des Beitrag

Eines sollte man beachten:
Das Programmieren ist kein Selbstzweck!
Ein Programm setzt eine definierte Aufgabe in Software um(, weil es so 
am einfachsten geht).

Das Ganze sieht dann sinngemäß folgendermaßen aus:
1. Es zeichnet sich eine Aufgabe ab, die zu lösen ist.
2. Die Aufgabe wird ausreichend durchdacht und dabei dokumentiert.
3. Der Benutzer des Ganzen versteht das Ergebnis von 2. und segnet es 
ab.
4. Die Lösung der Aufgabe wird aus Benutzersicht beschrieben und vom 
Benutzer abgesegnet.
5. Die Hardware für die Lösung wird konzipiert.
6. Das Design der Software erfolgt:
6.1 Grobdesign,
6.2 Feindesign bis herunter zum Pseudocode.
7. Die Hardware wird hergestellt.
8. Erst jetzt wird die Software programmiert, und zwar in den Pseudocode 
hinein.
9. Der Software-Produzent testet (White Box Test).
10. Der Benutzer nimmt das System ab (einschließlich Black Box Test).

Die Dauer der einzelnen Schritte kann hierbei von Minuten bis hin zu 
Jahren betragen. Das Ergebnis des Ganzen ist jedenfalls ein 
durchdachtes, sauber dokumentiertes, wartbares und (meist) 
funktionsfähiges System.
Der Anteil der eigentlichen Codierung am gesamten Zeitaufwand liegt 
erfahrungsgemäß bei weniger als 20%.

Zum Schluß noch eins: Wenn ein Programm kompliziert ist, dann stimmt 
etwas mit dem Programm nicht!

Grüße
Bernhard

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Genau, nochmal zu ein paar Ausgangsfragen zurück:

>Wie dokumentiert ihr Software? Immer, garnie oder im nachhinein?
Eigentlich nur durch selbsterklärende Funktions/Variablennamen und an 
komplizierteren Stellen vereinzelte Kommentare im Quelltext.

>Zeichnet ihr Struktorgramme oder einfach Kommentare?
Nur wenns nach 3 Versuchen im Kopf nicht hinhaut, dann aber lieber 
Flussdiagramme, Struktogramme mag ich irgendwie nicht.

von yalu (Gast)


Lesenswert?

Bitte entschuldigt, wenn ich das Topic wieder ein wenig verlasse. Habe
den folgenden Text vor etwa zwei Stunden geschriebeni, als der Inhalt
noch aktueller war, bin aber noch nicht dazu gekommen, ihn
abzuschicken:

Tim T. schrieb:
> aber bei gotos muss ich dir widersprechen.

Das sollte natürlich auch überhaupt kein Aufruf zur Verwendung von
Gotos sein, sondern eher einer gegen pauschale Verteufelungen im
Allgemeinen.

Martin Thomas schrieb:
> Aber vor allem in Funktionen mit vielen Verschachtelungen, bei denen
> z.B. sehr viele mögliche Fehlerzustände  abgefragt werden, vermeiden
> machmal "mit Bedacht" eingesetzte label und  ein paar gotos
> ausufernde und unübersichtliche if-else Konstrukte

Genau das ist der Fall, und wahrscheinlich der einzige, wo Gotos
sinnvoll sein können. Beispiel:
1
void function(void) {
2
    // Aktion 1
3
    if(Fehler1) goto error;
4
5
    // Aktion 2
6
    if(Fehler2) goto error;
7
8
    // Aktion 3
9
    if(Fehler3) goto error;
10
11
    // Aktion 4
12
    if(Fehler4) goto error;
13
14
    // Aktion 5
15
    if(Fehler5) goto error;
16
17
    goto end;
18
19
error:
20
    // Fehlerbehandlung
21
22
end:
23
    // abschließende Aktionen, die in jedem Fall ausgeführt werden
24
    // müssen
25
}

Hier wird sofort klar, dass nacheinander die Aktionen 1 bis 5
ausgeführt werden und im Fehlerfall in die gemeinsame
Fehlerbehhandlung verzweigt wird.

Dieselbe Funktion ohne Gotos:
1
void function(void) {
2
    int ok = 0;
3
4
    // Aktion 1
5
    if(!Fehler1) {
6
        // Aktion 2
7
        if(!Fehler2) {
8
            // Aktion 3
9
            if(!Fehler3) {
10
                // Aktion 4
11
                if(!Fehler4) {
12
                    // Aktion 5
13
                    if(!Fehler5) {
14
                        ok = 1;
15
                    }
16
                }
17
            }
18
        }
19
    }
20
21
    if(!ok) {
22
        // Fehlerbehandlung
23
    }
24
25
    // abschließende Aktionen, die in jedem Fall ausgeführt werden
26
    // müssen
27
}

Hier ist es nicht sofort offensichtlich, was beim Auftreten eines
Fehlers passiert. Um das zu erkennen, muss man sich mühsam die
If-Treppe am anderen Ende wieder hochhangeln (man stelle sich zudem
vor, die einzelnen Aktionen bestehen aus jeweils mehreren
Anweisungen, so dass der Code insgesamt länger wird).

Außerdem benötigt man eine izusätzliche Variable, um die
Erfolgsinformation aus der innersten If-Anweisung nach außen zu
tragen.

Ganz abgesehen davon wird der Code unnötig "breit", vor allem, wenn
man nicht nur 5 sondern vielleicht 20 Fehlerfälle zu untersuchen hat.

Ein Switch-Case in C ist auch nicht viel anderes als ein Mehrfach-
Goto, bei dem an Stelle der Labels abzuprüfende Werte stehen. Würde
man den Switch deswegen durch eine verschachtelte und mehrfach
eingerückte If-Anweisung ersetzen?

> Das ist dann im Prinzip ein realtiv übersichtliches, im Vergleich zu
> C++ allerdings recht primitives, exception-handling.

Genau richtig. Die C++-Exceptions sind für die Fehlerbehandlung wie im
obigen Beispiel gemacht. Damit kann man in C++ nicht nur Gotos,
sondern auch Longjumps auf saubere Art und Weise ersetzen.

Jetzt aber wieder zurück zur Ausgangsfrage ;-)

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Sorry aber dafür würde ich:
1
uint8_t FehlerInFunktion(void){
2
    // Aktion 1
3
    if(Fehler1) return 1;
4
5
    // Aktion 2
6
    if(Fehler2) return 1;
7
8
    // Aktion 3
9
    if(Fehler3) return 1;
10
11
    // Aktion 4
12
    if(Fehler4) return 1;
13
14
    // Aktion 5
15
    if(Fehler5) return 1;
16
17
return 0;
18
}
19
20
void function(void){
21
 if (FehlerInFunktion()){
22
  // Fehlerbehandlung
23
 };
24
 // abschließende Aktionen, die in jedem Fall ausgeführt werden
25
 // müssen
26
}
verwenden.

Aber ich will keine Endlosdiskussion starten, jeder wie er mag... und 
nun B2T

von yalu (Gast)


Lesenswert?

Was aber, wenn du für die Fehlerbehandlung ganz viele Variablen aus
den Aktionen 1 bis 5 brauchst? Die darin enthaltenen Werte müsstest du
irgendwie aus FehlerInFunktion() heraus- und in function()
hineinbekommen. Vielleicht ein Fall für globale Variablen? ;-)

Man müsste jetzt ein konkretes Anwendungsbeispiel parat haben. Ich
habe jetzt gerade keins hier, da der Fall zugegebenermaßen nicht allzu
oft auftaucht.

Aber ich denke, wenn jemand tatsächlich auf so einen Fall stößt, der
ohne Gotos nur ungeschickt gelöst werden kann, wird er es nach dem
bisher Geschriebenen wahrscheinlich selbst merken. Wie gesagt, es geht
mir ja nicht darum, dass jetzt jeder seinen bereits funktionsfähigen
Code mit Gotos spickt. Von Gotos ist nach wie vor abzuraten, nur
generell vertaufeln sollte man es nicht.

von Matthias L. (Gast)


Lesenswert?

Ich breche alle Konzepte auf saubere State-Maschines runter.

DIese sind (zuerst) unabhängig voneinander und könnn sich nur durch 
funktion(saufrufe) beeinflussen...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.