Forum: Mikrocontroller und Digitale Elektronik C-Variablen nur vorübergehend?


von AVRli .. (avrli)


Lesenswert?

Hi,

wie ist es möglich in C Variablen für eine bestimmte Zeit im RAM zu 
nutzen?
Ich habe eine Funktion, welche wenn sie aufgerufen wird 34 uint_16 Werte 
benötigt.

Die Daten werden allerdings über mehrere Funktionen gesammelt und 
ausgewertet, das allerdings nicht ständig! Es würden 68 Byte ständig 
belegen was Verschwendung wäre.

Gibt es sowas wie:
- erstelle 34 uint_16 Variablen
ini();
calc();
out();
- lösche die 34 uint_16 Variablen wieder


Danke für jede Hilfe!
Gruß AVRli...

von Dirk (Gast)


Lesenswert?

Hallo,

ja das gibts: Den Stack... deklariere die 34 Variablen innerhalb
einer Funktion, dann leben sie bis zu deren Ende:
1
void maches ()
2
{
3
  int bla1 = 123;
4
  int blubb = 321;
5
  // und so weiter [1]
6
  ini();
7
  calc();
8
  out();
9
}

Grüße,
Dirk

[1] Wenn es der selbe Typ ist, mach ein Array draus!

von Rolf M. (rmagnus)


Lesenswert?

Dirk schrieb:
> Hallo,
>
> ja das gibts: Den Stack... deklariere die 34 Variablen innerhalb
> einer Funktion, dann leben sie bis zu deren Ende:
> void maches ()
> {
>   int bla1 = 123;
>   int blubb = 321;
>   // und so weiter [1]
>   ini();
>   calc();
>   out();
> }

Damit die Funktionen auch darauf zugreifen können:
1
void ini(uint16_t* werte);
2
void calc(uint16_t* werte);
3
void out(uint16_t* werte);
4
5
void maches(void)
6
{
7
    uint16_t werte[34];
8
    ini(werte);
9
    calc(werte);
10
    out(werte);
11
}

Beim Verlassen von "maches" wird der Platz automatisch wieder 
freigegeben.

von AVRli .. (avrli)


Lesenswert?

Danke, innerhalb einer Funktion ist bekannt.
Mein Problem ist dabei, dass die Aktionen nicht alle in eine einzelne 
Funktion hintereinander ablaufen.

Die Daten werden via UART eingesammelt, das Main muss in der Zeit weiter 
laufen.

Zur Zeit habe ich die 64 Werte global im Main definiert, das 
funktioniert schon mit dem Nachteil der Verschwendung, wenn ich den Teil 
nicht benötigt wird.

Gruß AVRli...

von Thomas E. (thomase)


Lesenswert?

AVRli .. schrieb:
> mit dem Nachteil der Verschwendung

Verschwendung von was?

von Tobias B. (Firma: www.elpra.de) (ttobsen) Benutzerseite


Lesenswert?

AVRli .. schrieb:
> Zur Zeit habe ich die 64 Werte global im Main definiert, das
> funktioniert schon mit dem Nachteil der Verschwendung, wenn ich den Teil
> nicht benötigt wird.

Dann willst du wohl mit dem Heap arbeiten.

Siehe:

https://de.wikipedia.org/wiki/Dynamischer_Speicher

von A. S. (rava)


Lesenswert?

das ist aber einfach so.

Eine Lösung für sowas ist dynamische Speicherallokierung. Dafür brauchst 
du aber ein Betriebssystem, oder du musst dir selber einen 
Speichermanager schreiben.

Beides lohnt für Mikrocontroller in den wenigsten Fällen.


Stell dir mal die Frage: Wann könnte der Speicher denn immer frei 
gegeben werden? Wer wird den Speicher dann weiterverwenden? Kannst du 
das mit Worten beschrieben?

Wenn ja, ist ziemlich wahrscheinlich, dass die Lösung von Dirk & Rolf 
für dich umsetzbar ist. Wenn nein, dann brauchst du den Speicher 
ziemlich sicher dauerhaft.

von S. R. (svenska)


Lesenswert?

A. S. schrieb:
> Wenn nein, dann brauchst du den Speicher
> ziemlich sicher dauerhaft.

Und wenn du ihn nicht dauerhaft brauchst, dann solltest du darüber 
nachdenken, was passiert, wenn du ihn kurzzeitig brauchst und er gerade 
nicht verfügbar ist. Auf Mikrocontrollern kann das durch Fragmentierung 
sehr schnell passieren.

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


Lesenswert?

A. S. schrieb:
> Eine Lösung für sowas ist dynamische Speicherallokierung. Dafür brauchst
> du aber ein Betriebssystem,

Wie kommst du denn auf diesen Trichter?

malloc() gibt's auch für AVRs nun schon seit geraumer Zeit – ganz ohne 
Betriebssystem.

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


Lesenswert?

S. R. schrieb:

> Und wenn du ihn nicht dauerhaft brauchst, dann solltest du darüber
> nachdenken, was passiert, wenn du ihn kurzzeitig brauchst und er gerade
> nicht verfügbar ist.

Ja.

Das braucht man übrigens in solchen Fällen auch dann, wenn man alles 
statisch vorbelegt – aber dann mehr Anforderung reinkommt, als vorbelegt 
worden war. Anders gesagt, dynamische Speicheranforderungen, gleich wie 
sie bedient werden, müssen immer eine Strategie haben, wie sie mit 
Ressourcenknappheit umgehen.

> Auf Mikrocontrollern kann das durch Fragmentierung
> sehr schnell passieren.

Keineswegs – nicht in dieser Pauschalität (auch, wenn das immer wieder 
gern rezitiert wird).

Fragmentierung gibt's erstens sowieso nur, wenn man unterschiedlich 
große Blöcke braucht und dann verschieden wieder freigibt. Klang mir 
beim TE nicht unbedingt so, aber vielleicht hat er's auch nur nicht ganz 
verständlich formuliert.

Zweitens ist Fragmentierung vor allem dann ein Problem, wenn die 
Belegung und Freigabe nicht wirklich sehr zufällig ist. Sofern das 
tatsächlich guter Zufall ist und stets im Mittel „ein wenig mehr“ an 
Speicher da ist als insgesamt nötig ist, dann klappt das mit dem 
Sich-selbst-Defragmentieren ganz gut. Selbstverständlich wirst du immer 
einen pathologischen Fall konstruieren können, der fragmentiert … nur 
ist der bei wirklich zufälliger Belegung nicht sehr praxisrelevant.

Wie viel das „ein wenig mehr“ tatsächlich ist, müsste man mit einer 
Monte-Carlo-Simulation ermitteln (die natürlich auch eine 
Restwahrscheinlichkeit enthält, dass alle Ressourcen aufgebraucht sind). 
Rein vom Gefühl her denke ich, dass man schon mit ca. 20 % an Reserve 
eine ziemlich hohe Sicherheit hat, dass es funktioniert.

Aber wie geschrieben, das setzt voraus, dass die Ereignisse (also wann 
wird welche Blockgröße benötigt und wie lange) tatsächlich zufällig 
verteilt sind.

von AVRli .. (avrli)


Lesenswert?

Vergessen habe ich natürlich was ich benutze...
ATmega2560 mit Atmel Studio 7 und AVR GCC.

Sicher kann ich die 64 Bate auch einfach dauerhaft "verballern" nur 
"schön" finde ich es nicht und wer weiß was kommt, vielleicht sind es in 
einem anderen Projekt mal deutlich mehr?

Jörg W. schrieb:
> malloc() gibt's auch für AVRs

Da werde ich mal schauen ob ich da was finde... DANKE!

von Rolf M. (rmagnus)


Lesenswert?

AVRli .. schrieb:
> Danke, innerhalb einer Funktion ist bekannt.
> Mein Problem ist dabei, dass die Aktionen nicht alle in eine einzelne
> Funktion hintereinander ablaufen.
>
> Die Daten werden via UART eingesammelt, das Main muss in der Zeit weiter
> laufen.
>
> Zur Zeit habe ich die 64 Werte global im Main definiert, das

(Oben waren es 34)

> funktioniert schon mit dem Nachteil der Verschwendung, wenn ich den Teil
> nicht benötigt wird.

Das heißt du brauchst den Platz dann zwischendurch für was anderes? Ist 
sichergestellt, dass den Platz nie für zwei Sachen gleichzeitig 
brauchst?
Für das, was du beschreibst, ist, wie schon erwähnt wurde, malloc() 
gedacht:
1
uint16_t* werte = malloc(64 * sizeof *werte);
Dann kannst du über diesen Zeiger dein Array benutzen, auch über 
Funktionsgrenzen hinweg. Und wenn du fertig bist, machst du:
1
free(werte);

Jörg W. schrieb:
> Fragmentierung gibt's erstens sowieso nur, wenn man unterschiedlich
> große Blöcke braucht und dann verschieden wieder freigibt. Klang mir
> beim TE nicht unbedingt so, aber vielleicht hat er's auch nur nicht ganz
> verständlich formuliert.

Naja, er will den Speicher an der Stelle dynamisch allokieren, damit er 
ihn an anderen Stellen für was anderes verwenden kann. In was für 
Blockgrößen dort allokiert wird, ist aber völlig unbekannt.
Wenn er immer nur genau einen 34 oder 64 Werte großen allokiert und dann 
wieder deallokiert, bringt ihm das dynamische Speichermanagement ja eher 
wenig.

> Zweitens ist Fragmentierung vor allem dann ein Problem, wenn die
> Belegung und Freigabe nicht wirklich sehr zufällig ist. Sofern das
> tatsächlich guter Zufall ist und stets im Mittel „ein wenig mehr“ an
> Speicher da ist als insgesamt nötig ist, dann klappt das mit dem
> Sich-selbst-Defragmentieren ganz gut.

Auf einem PC mit Gigabytes an RAM ist das kein Problem. Auf einem AVR, 
der wenn's hoch kommt ein paar kB hat, sieht das aber etwas anders aus.

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


Lesenswert?

Rolf M. schrieb:
> Auf einem AVR, der wenn's hoch kommt ein paar kB hat, sieht das aber
> etwas anders aus.

Die Frage ist nicht die absolute Speichergröße, sondern wie viel davon 
in „Spitzenzeiten“ etwa maximal alloziert wird. Solange das gut unter 
der freien RAM-Größe ist, sortiert sich ein stochastisch arbeitendes 
System mit hoher Wahrscheinlichkeit (aber natürlich nicht mit 100%iger 
Sicherheit!) wieder selbst passend. Ist vom Prinzip her ein bisschen wie 
das CSMA/CD beim Ethernet: solange dort noch ein wenig „Luft“ auf dem 
Medium ist, ist die Wahrscheinlichkeit hoch, dass mein Datenpaket auf 
den Draht darf, auch, wenn es eben nicht garantierbar ist. Konkurrent 
Token Ring garantierte die Verfügbarkeit zwar – aber einen wirklichen 
Vorteil brachte das erst bei weit über 90 % Medienauslastung. 
Mittlerweile redet keiner mehr über den „Toten Ring“ …

Das oft empfohlene „allozier doch genügend statischen Speicher vorab“ 
würde in vergleichbaren Szenarien natürlich schon viel eher an seine 
Grenze stoßen, denn dort muss ich meine Allokationseinheit an der Größe 
der maximalen Einzelanforderung ausrichten (und dann <N> solcher 
Einheiten vorab allozieren). Alle Anforderungen, die weniger als das 
brauchen, verschwenden daher Speicher. Im Mittel wird dann also die 
Verschwendung größer sein, oder eben anders gesagt, die 
Ressourcenverknappung bereits viel eher eintreten.

: Bearbeitet durch Moderator
von Shared memory (Gast)


Lesenswert?

Was ist der Sinn und Zweg von unions.
Denkt mal darüber nach. ?

von S. R. (svenska)


Lesenswert?

Statische Speicherallokation ist pessimistisch: Ich verschwende Speicher 
für die Garantie, dass mein Bedarf immer gedeckt ist.

Dynamischer Speicher ist optimistisch: Ich erlaube die Mehrfachnutzung 
des vorhandenen Speichers in der Hoffnung, meinen Bedarf trotzdem fast 
immer decken zu können.

In beiden Fällen muss ich meinen Bedarf sinnvoll abschätzen können. Aber 
nur im dynamischen Fall muss ich auch damit umgehen können, dass malloc 
jederzeit fehlschlagen kann. Auch wenn pathologische Fälle statistisch 
nicht auftreten, kann ein bösartiger Angreifer sie oft auch absichtlich 
erzeugen. Sowas lässt sich nur schwer ausschließen.

Unions sind kein allgemeiner Ersatz für dynamischen Speicher.

von A. S. (rava)


Lesenswert?

Jörg W. schrieb:
> A. S. schrieb:
>> Eine Lösung für sowas ist dynamische Speicherallokierung. Dafür brauchst
>> du aber ein Betriebssystem,
>
> Wie kommst du denn auf diesen Trichter?
>
> malloc() gibt's auch für AVRs nun schon seit geraumer Zeit – ganz ohne
> Betriebssystem.

bitte nur ganze Sätze zitieren ;)
Offensichtlich gibt's für den AVR einen Manager fertig in einer 
Bibliothek. Gut für alle, die sich trauen, so etwas zu benutzen.

Genauso könnte man dem Threadersteller übrignes "union" empfehlen. Damit 
kann man Speicher doppelt benutzen - nur eben nicht gleichzeitig.
Ist vielleicht sogar weniger gefährlich, weil es den Erfinder zwingt ein 
deterministisches System zu bauen...

Meine grundsätzliche Empfehlung wäre es, stochastische Unsicherheiten 
unter Kontrolle zu bringen, bevor man auch noch mit knappem Speicher 
kämpfen muss.

von Jemand (Gast)


Lesenswert?

Jörg W. schrieb:
> Anders gesagt, dynamische Speicheranforderungen, gleich wie sie bedient
> werden, müssen immer eine Strategie haben, wie sie mit
> Ressourcenknappheit umgehen.

Ich glaube in 99,x % der Fälle ist das stumpfes Abstürzen. Bei Linux 
auch gerne in Zeitlupe.

von HyperMario (Gast)


Lesenswert?

AVRli .. schrieb:
> - lösche die 34 uint_16 Variablen wieder

wer oder was soll denn den "freien Speicher" in er Zwischenzeit Nutzen? 
Soll er Tamagotchi II / Moorhuhn extended edition spielen bis du ihn 
wieder brauchst ;-) ?

von AVRli .. (avrli)


Lesenswert?

A. S. schrieb:
> Genauso könnte man dem Threadersteller übrignes "union" empfehlen.

Mir geht es primär um den Zustand das ich für eine Routine, die vlt. 
einmal in der ganzen Lebenszeit der Platine genutzt wird, der Speicher 
"weg ist". Klar kann man argumentieren, ist doch egal.

Auch wenn sich einige darüber lustig machen, mich interessiert wie man 
Resourcen sparend programmiert.

malloc(); scheint für dene inen Fall auch nicht das richtige zu sein.
"Union" ist auch neu für mich, das schau ich mir jetzt mal an.

Danke für alle ernsten Antworten!
Gruß AVRli...

von Barrex (Gast)


Lesenswert?

OK, mit dynamischer Speicherverwaltung kannst du den RAM verwalten. Die 
Speicherverwaltung selbst verballert aber ziemlich viel Programmspeicher 
und Laufzeit.

Auf einem Mikrocontroller würde ich eine dynamische Speicherverwaltung 
daher nur in Ausnahmefällen benutzen, wenn es gar nicht anders geht.

Je nach Norm ist eine dynamische Speicherverwaltung bei 
sicherheitsrelevanter Programmierung (sicher im Sinne safety) sogar 
verboten.

von Peter D. (peda)


Lesenswert?

AVRli .. schrieb:
> Sicher kann ich die 64 Bate auch einfach dauerhaft "verballern" nur
> "schön" finde ich es nicht

Es gibt fürs Programmieren keinen Schönheitspreis.

Du kannst natürlich eine Union erstellen, um die 64 Byte noch 
anderweitig zu verwenden. Nur mußt Du Dir dann auch 101%-ig sichern 
sein, daß sich beide Anwendungen nie in die Quere kommen. In der Regel 
handelst Du Dir damit noch viel mehr Ärger ein, als mit 0,8% 
"Verschwendung".

von AVRli .. (avrli)


Lesenswert?

Barrex schrieb:
> Die
> Speicherverwaltung selbst verballert aber ziemlich viel Programmspeicher
> und Laufzeit.

Gut Laufzeit wäre vlt. noch vernachlässigbar in meinem Fall, 
Programmspeicher hingegen ist natürlich auch "kostbar".
Ich lasse es mit malloc();


Peter D. schrieb:
> Es gibt fürs Programmieren keinen Schönheitspreis.

Das glaube ich gerne! :-D


Peter D. schrieb:
> Du kannst natürlich eine Union erstellen, um die 64 Byte noch
> anderweitig zu verwenden. Nur mußt Du Dir dann auch 101%-ig sichern
> sein, daß sich beide Anwendungen nie in die Quere kommen.

Das bin ich mir.
Ich brauche die Union wenn dann nur im Setup und da kann immer nur ein 
Parameter zur gleichen Zeit festgelegt werden.

Ich werde es mit Union einfach mal probieren, habe ich noch nie gemacht. 
Ist mal was neues...

Danke für Eure Vorschläge und Erklärungen zum Für und Wieder.
Gruß AVRli...

von Mach (Gast)


Lesenswert?

Auch bei der Funktionsvariante, d.h. temporaeres Speichern auf dem 
Stack, braucht man Speicherplatz. In diesem Fall auf dem Stack. Ich 
vermeide es immer, groessere Datenmengen auf den Stack zu packen, man 
(ich) hat den Stackbedarf sowieso nicht im Blick. Die 60 Variablen 
zusaetzlich auf dem Stack sind bei der Initalisierung, wenn es keine 
tiefen Funktionsverschachtelungen gibt, vielleicht aber kein Problem.

Der Union-Vorschlag scheint mir nicht schlecht, aber das wird man nur 
machen, wenn der Speicher tatsaechlich knapp wird. Mit dynamischem 
Speicher zu arbeiten ist aber auch so eine Sache.

Im Grunde sind das halt alles Kompromisse, auf die man erst dann 
zugreifen sollte, wenn die Anwendung das verlangt.

von S. R. (svenska)


Lesenswert?

AVRli .. schrieb:
> Mir geht es primär um den Zustand das ich für eine Routine, die vlt.
> einmal in der ganzen Lebenszeit der Platine genutzt wird, der Speicher
> "weg ist". Klar kann man argumentieren, ist doch egal.

Wie gesagt, im Normalfall würde man in so einem Fall die Variablen in 
der Routine auf dem Stack anlegen, dann verschwinden sie automatisch am 
Ende der Funktion. Das geht bei dir nicht, was ich seltsam finde. 
Eventuell könnte man die Programmstruktur anpassen, dass es so geht.

Ansonsten gilt: Für ungenutzten Speicher bekommst du kein Geld zurück. 
Wenn dein restliches Programm also 64 Bytes übrig lässt, dann kannst du 
die ruhig fürs Setup reservieren - dann sind sie wenigstens manchmal zu 
was nütze.

: Bearbeitet durch User
von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

S. R. schrieb:
> Statische Speicherallokation ist pessimistisch: Ich verschwende Speicher
> für die Garantie, dass mein Bedarf immer gedeckt ist.

Nur, wenn du ein dynamisches Problem hast (nur dann hat eine dynamische 
Speicherzuweisung überhaupt Sinn), dann weißt du nicht vorab, wie viele 
Anforderungen ggf. auf einmal eintreffen werden. Du hast folglich auch 
da keinerlei Garantie, dass der Bedarf immer gedeckt ist.

Die einzige Garantie, die du hast ist, dass dir kein malloc() ein NULL 
zurückgeben kann. Stattdessen sind dann halt die Slots deines 
vorbelegten Arrays alle … der Effekt bleibt der gleiche. Darum schrieb 
ich ja, wenn man so ein Problem hat, dann braucht man immer eine 
Strategie, wie man damit umgeht, dass man die ankommenden Anforderungen 
jetzt gerade doch nicht bedienen kann. Das kann sein, dass man jetzt 
einfach am besten neu startet, kann auch sein, dass man eben die nicht 
bedienbaren Anforderungen ignorieren muss. Vielleicht kann man ja 
demjenigen, der die Anforderung initiiert hat, noch einen Hinweis 
darüber geben. Hängt sehr von der Situation ab.

A. S. schrieb:
> bitte nur ganze Sätze zitieren ;)

Hätte auch nichts geholfen, dieweil hier nicht zutreffend. Daher hatte 
ich ihn weggelassen.

Mach schrieb:
> Auch bei der Funktionsvariante, d.h. temporaeres Speichern auf dem
> Stack, braucht man Speicherplatz. In diesem Fall auf dem Stack.

Im Gegensatz zu malloc() hat man dort übrigens auf einem kleinen 
Controller (ohne MPU) keinerlei Garantie, dass der Stack dann nicht 
ggf. mit den statischen Daten kollidiert. Das ist noch viel fataler als 
ein malloc(), das einem wenigstens noch sauber mit NULL signalisieren 
kann, dass jetzt der Speicher alle ist. Solcherart Bugs zu suchen macht 
alles andere als Spaß, denn sie treten nur aller Jubeljahre auf und 
werden erst viel später bemerkt (nämlich dann, wenn mal wieder jemand 
die zerstörten statischen Daten braucht).

AVRli .. schrieb:
> Gut Laufzeit wäre vlt. noch vernachlässigbar in meinem Fall,
> Programmspeicher hingegen ist natürlich auch "kostbar".

Ich vermute zwar nicht, dass malloc() für dich wirklich eine großartige 
Lösung ist, aber so extrem ist der Speicherbedarf nun auch wieder nicht: 
ca. 0,5 KiB.  Für eine einmalige Aktion sicher nicht sinnvoll, wenn man 
es wirklich braucht, in der Regel kompakter als irgendwelche Versuche 
eines eigenen Speichermanagements – und mittlerweile wahrscheinlich bis 
zum letzten Bit debuggt. :-)

von S. R. (svenska)


Lesenswert?

Jörg W. schrieb:
> Nur, wenn du ein dynamisches Problem hast (nur dann hat eine dynamische
> Speicherzuweisung überhaupt Sinn), dann weißt du nicht vorab, wie viele
> Anforderungen ggf. auf einmal eintreffen werden. Du hast folglich auch
> da keinerlei Garantie, dass der Bedarf immer gedeckt ist.

Das meinte ich mit "den Bedarf sinnvoll abschätzen". Wobei mein 
Bauchgefühl sagt, dass die meisten Probleme für kleinere Mikrocontroller 
(d.h. der AVR-Klasse) ohnehin nicht dynamisch sind. Ich muss vorher 
festlegen, wieviele Anfragen ich verarbeiten können will und was mit dem 
Rest passiert, dafür bekomme ich aber die Garantie, dass das auch 
(unabhängig vom restlichen Systemzustand) klappt.

Wenn in meinem Code ständig Puffer alloziiert und freigegeben werden, 
dann habe ich nur eine statistische Abschätzung, dass ich N Anfragen 
bearbeiten kann. Wenn das Timing ungünstig ist, können es auch mal 
weniger sein. Dafür ist N wahrscheinlich größer als im statischen Fall.

Es ist immer eine Kompromisslösung. Bisher bin ich mit statischen 
Allokationen ausgekommen, oder hatte malloc()-Aufrufe ausschließlich vor 
der Hauptschleife.

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


Lesenswert?

S. R. schrieb:
> Bisher bin ich mit statischen Allokationen ausgekommen, oder hatte
> malloc()-Aufrufe ausschließlich vor der Hauptschleife.

Ich habe malloc() auch auf AVRs schon benutzt (klar, die Implementierung 
in der avr-libc ist ja von mir ;), aber auf aktuellen kommerziellen 
ARM-Projekten hat die Umstellung von einer vormals handgestrickten, 
vor-allozierten Lösung auf striktes malloc() für alles, was "on demand" 
ist, einen deutlich klareren, saubereren und stabileren Code bewirkt. 
Klar, die Teile sind nun keine kleinen Controller mehr (aber der 
ATmega2560 ist das auch nicht).

Man sollte sich aber immer vergegenwärtigen, dass UNIX (und damit auch 
malloc()) auf einer PDP-11 mit gerade mal 2 x 64 KiB Adressraum (je 
einmal für Befehle und Daten) groß geworden ist.

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.