Forum: PC-Programmierung Problem mit einer als static deklarierten Funktion


von Statiker (Gast)


Lesenswert?

Ich habe einen Code-Schnipsel aus einem Example in C per c&p in eine 
Datei application_1.cpp verschoben.

In application_1.cpp:
1
void NVICtest_1(void){
2
    if(HAL_Init()!= HAL_OK)
3
    {
4
      /* Start Conversation Error */
5
      Error_Handler();
6
    }
7
8
    ...
9
    ...
10
11
}
12
13
static void Error_Handler(void)
14
{
15
  /* Turn LED3 on */
16
  BSP_LED_On(LED3);
17
  while(1);
18
}

In application_1.hpp:
1
void NVICtest_1(void);
2
static void Error_Handler(void);

Das führt zu den Warnungen:
'void Error_Handler()' declared 'static' but never defined 
[-Wunused-function] C/C++ Problem

Unused static function 'Error_Handler' application_1.cpp
Code Analysis Problem

Wird 'static' in C++ anders betrachtet als in C? Oder was isch da los?

: Verschoben durch Admin
von Rolf Magnus (Gast)


Lesenswert?

Die Bedeutung ist in beiden Sprachen gleich. In beiden ergibt es 
keinerlei Sinn, diese static-Funktion in einem Header zu deklarieren.

von Peter II (Gast)


Lesenswert?

Statiker schrieb:
> Wird 'static' in C++ anders betrachtet als in C? Oder was isch da los?

static bei Funktionen sagt dem Compiler das sie nur in diesem modul 
verwendet werden. Es macht in deinen Fall also keine sinn. Warum willst 
du sie static machen?

von Hans (Gast)


Lesenswert?

Du solltest die static-Funktion nicht im Headerfile deklarieren, sondern 
am Anfang des CPP-Files.

Denn sonst deklarierst Du in jedem anderen CPP-File, das 
application_1.hpp inkludiert, die static-Funktion, obwohl sie in den 
anderen CPP-Files nicht vorhanden ist. Das ergibt dann die Warnung.

von Statiker (Gast)


Lesenswert?

Hans (Gast) schrieb:
>Du solltest die static-Funktion nicht im Headerfile deklarieren, sondern
>am Anfang des CPP-Files.

>Denn sonst deklarierst Du in jedem anderen CPP-File, das
>application_1.hpp inkludiert, die static-Funktion, obwohl sie in den
>anderen CPP-Files nicht vorhanden ist. Das ergibt dann die Warnung.
Jetzt wo du es schreibst...
Danke.

von nur malso (Gast)


Lesenswert?

rein aus Neugierde,
welchen Sinn macht es denn  ein C-Programm in eine cpp file zu packen?
würde es sich hier nicht anbieten im Header eine Klasse mit public und 
in dem BSP. von oben privat Funktionen zu erzeugen?

Habe selber mit c++ allerdings noch nicht so furchtbar viel gemacht...

von Statiker (Gast)


Lesenswert?

>welchen Sinn macht es denn ein C-Programm in eine cpp file zu packen?
Das ist ne laaange verkorkse Geschichte (die viele Fürsprecher hat), 
verbunden mit der philosophischen Frage was wann richtig und was falsch 
ist...

von Karl H. (kbuchegg)


Lesenswert?

nur malso schrieb:
> rein aus Neugierde,
> welchen Sinn macht es denn  ein C-Programm in eine cpp file zu packen?

Es gibt ein 'Sprichwort' wonach C++ das bessere C ist.

Das 'C-Subset' von C++ unterscheidet sich vom echten C in ein paar 
Punkten. Von den meisten derartigen Unterschieden muss man sagen: die 
C++ Variante ist besser und hätte eigentlich in C von Anfang an so sein 
sollen.

Ein Beispiel: enum sind in C nichts weiter als verpackte Integer. In C++ 
sind es aber echte Datentypen.
Das folgende Programm
1
#include "stdio.h"
2
3
enum Karte { Herz, Pik, Kreuz, Treff };
4
enum Farbe { Rot, Schwarz };
5
6
void foo( enum Karte arg )
7
{
8
  printf( "foo\n" );
9
}
10
11
int main(int argc, char* argv[])
12
{
13
  foo( Rot );
14
}
(man beachte den Datentypfehler beim Aufruf von foo) compiliert 
anstandslos in C, nicht aber in C++.

Auch das in C ein void-Pointer einfach so mirnichts dirnichts an jeden 
anderen Pointertyp zuweisbar ist, ist etwas was man eigentlich nicht 
haben will.

Die Kleinigkeit, dass der Name einer Struktur automatisch ein eigener 
Datentyp wird (kein typedef erforderlich), ist ein nettes kleines C++ 
Feature von dem man sich fragt, warum das in C nicht auch gleich so 
gemacht wurde.

Und so gibt es noch ein paar Kleinigkeiten, in denen sich ein C++ 
Compiler beim compilieren eines reinen C-Codes zum Wohle des 
Programmierers auswirkt.

Da die meisten Compiler sowieso Kombicompiler sind, die von einem 
Zwischencode weg die Optimierungsstufe und Codegenerierung abarbeiten 
und sich nur darin unterscheiden, welcher Satz von Regeln bei der 
Übertragung von C bzw. C++ in diesen Zwischencode zur Anwendung kommt, 
ist die Codequalität die hinten raus kommt normalerweise bei gleichem 
Source Code identisch und nicht davon abhängig, ob der C++ oder der C 
Compiler sich durch den Source geackert hat. Der einzige wirkliche 
Unterschied der bleibt ist damit, dass der C++ Compiler an ein paar 
(sinnvollen) Stellen pingeliger ist als der C Compiler.
Zumindest fällt mir jetzt auf Anhieb kein gegenteiliges (negativ) 
Beispiel ein. :-)

: Bearbeitet durch User
von Torsten R. (Firma: Torrox.de) (torstenrobitzki)


Lesenswert?

nur malso schrieb:
> rein aus Neugierde,
> welchen Sinn macht es denn  ein C-Programm in eine cpp file zu packen?

Es ist ein Irrglaube, dass in C++ die Klasse das einzige, Struktur 
gebende Element wäre. Wenn etwas günstiger als Funktion modellierbar 
ist, sollte man auch in C++ eine Funktion draus machen.

Ansonsten hat C++ z.B. namespaces, templates, striktere Typ-Prüfungen, 
keinen eigenen namespace für structs und wahrscheinlich vieles mehr, was 
einem die Arbeit erleichtert und angenehmer macht.

von temp (Gast)


Lesenswert?

Karl Heinz schrieb:
> Zumindest fällt mir jetzt auf Anhieb kein gegenteiliges (negativ)
> Beispiel ein. :-)

Eins wäre das name mangling von C++. Das zwingt einem häufig die 
Verwendung von extern "C" auf. Kein Problem wenn man weiß wie und warum. 
Aber bis es soweit ist schafft es manchmal Frust.

von Foka M. (foka)


Lesenswert?

Karl Heinz schrieb:
> Zumindest fällt mir jetzt auf Anhieb kein gegenteiliges (negativ)
> Beispiel ein. :-)

Naja, vielleicht haette ich zwei...

Ich schreibe eigentlich immer sehr gerne C++ Code, dennoch sind IMHO in 
C einige Details ganz gut geloest und erleichtern das 'Leben':
1. Struct Initialisierung mittels Membername.
2. In C++ kann ein character array, welches ein struct member ist, nicht 
sinnvoll initialisiert werden:
1
typedef struct {
2
  int someInt;
3
  const char someTxt[];
4
} MyTypeT;
5
6
const MyTypeT a = {42, "geht in C++ so nicht"};

Punkt 1 ist einfach nett, wohingegen Punkt 2. mich wirklich nervt.

Ich weiss in C++ sind char-arrays Vergangenheit und man sollte 
std::string verwenden. Im embedded Bereich braucht man strings trotzdem 
ab und zu, aber ein std::string will ich dafuer nicht nehmen.
Das tritt oeffters mal auf, wenn man 3-rd party code oder libs 
einbindet.
Ich versuche mir einfach dadurch zu helfen, dass in einem sepraraten *.c 
file die Initialisierung globaler Variablen von diesem Typ erfolgt und 
in *.cpp 'extern' referenziert wird. Soll die Variable aus irgend einem 
Grund auf den Stack, dann geht es nicht (darf aber auch nicht vorkommen, 
wenn man 'someTxt' aendern will).

Ansonsten, bei allem was Du schreibst, bin ich voll bei Dir und werde 
meine 8-Bitter weiterhin, so weit wie moeglich, in C++ programmieren ;-)

-Foka

Ps. Wenn jemand eine elegante C++ Loesung fuer das 
char-array-im-struct-Problem hat, wuerde ich mich sehr freuen diese 
kennen zu lernen!

von Osterhase (Gast)


Lesenswert?

Das Problem ist, dass someTxt[] kein Array, sondern ein Pointer ist. Es 
ist eine andere Schreibweise für: const char *someTxt;

Der C-Compiler schreibt den Text ins Programm und kopiert die Adresse 
des Texts nach someTxt. Fertig.

Der C++-Compiler versucht nach meinem Verständnis den Text an den 
Pointer zuzuweisen, was natürlich Unsinn ist, schon alleine weil die 
Typen nicht passen.

Lösung: Ein richtiges Array erzeugen, mit dem Text initialisieren und 
dann den Pointer setzen.

von Markus F. (mfro)


Lesenswert?

Foka Mokra schrieb:
> Karl Heinz schrieb:
>> Zumindest fällt mir jetzt auf Anhieb kein gegenteiliges (negativ)
>> Beispiel ein. :-)
>
> Naja, vielleicht haette ich zwei...
>
> Ich schreibe eigentlich immer sehr gerne C++ Code, dennoch sind IMHO in
> C einige Details ganz gut geloest und erleichtern das 'Leben':
> 1. Struct Initialisierung mittels Membername.
> 2. In C++ kann ein character array, welches ein struct member ist, nicht
> sinnvoll initialisiert werden:
>
>

Das kann doch der Konstruktor übernehmen:
1
typedef struct t {
2
    int someint;
3
    const char *someTxt;
4
    t(int someint, const char *someTxt) { this->someint = someint; this->someTxt = someTxt; }
5
} MyTypeT;
6
7
MyTypeT m = MyTypeT(10, "Hallo");

von Markus F. (mfro)


Lesenswert?

P.S.: natürlich funktioniert das nur, wenn's statt eines "flexible 
arrays" auch ein Zeiger sein darf, ansonsten: das gibt's halt nicht in 
C++

: Bearbeitet durch User
von Fabian O. (xfr)


Lesenswert?

Foka Mokra schrieb:
> Ich schreibe eigentlich immer sehr gerne C++ Code, dennoch sind IMHO in
> C einige Details ganz gut geloest und erleichtern das 'Leben':
> 1. Struct Initialisierung mittels Membername.
> 2. In C++ kann ein character array, welches ein struct member ist, nicht
> sinnvoll initialisiert werden:

Das sind allerdings beides C99 Features, die nur wenige Compiler 
beherrschen. Wenn der Code portabel sein soll, ist das nicht zu 
empfehlen.

Ein Array in einer Struktur kann man natürlich auch in C++ anlegen, 
sofern man die Länge in der Deklaration angibt. Oder Du nimmst einen 
Zeiger. Das lässt sich beides auch ohne selbstdefinierten Konstruktor 
initialisieren.

: Bearbeitet durch User
von Foka M. (foka)


Lesenswert?

Fabian O. schrieb:
> Ein Array in einer Struktur kann man natürlich auch in C++ anlegen,
> sofern man die Länge in der Deklaration angibt. Oder Du nimmst einen
> Zeiger. Das lässt sich beides auch ohne selbstdefinierten Konstruktor
> initialisieren.

Klar,
wenn ich es selbst in der Hand habe ist es kein Thema.

Das Problem, wie ich oben geschrieben habe, tritt vorwiegend im 
Zusammenhang mit 3-rd party code oder libraries. Ich habe also nicht die 
Moeglichkeit den Code zu aendern (oder nur sehr aufwaendig).

C ist eben nicht mehr einfach nur ein Subset von C++. Deswegen kann die 
Verwendug von C-libraries in C++ code, unter Umstaenden, etwas 
problematisch sein. Darueber muss man sich halt im klaren sein.

Uebrigens einfach durch 'const char* myText;' ersetzen ist auch nicht 
immer die Loesung. Hier ein Beispiel was der gcc aus beiden macht:
1
typedef struct A{
2
   int myInt;
3
   const char* someText;
4
} AT;
5
6
typedef struct A2{
7
   int myInt;
8
   const char someText[];
9
} A2T;
10
11
const AT a = {42, "das geth in C++ nicht" };
12
const A2T a2 = {43, "das geth in C++ nicht" };

Ein
avr-gcc --save-temps charArrInStruct.c
macht daraus:
1
.global  a
2
  .section  .rodata
3
.LC0:
4
  .string  "das geth in C++ nicht"
5
  .type  a, @object
6
  .size  a, 4
7
a:
8
  .word  42
9
  .word  .LC0
10
.global  a2
11
  .type  a2, @object
12
  .size  a2, 2
13
a2:
14
  .word  43
15
  .string  "das geth in C++ nicht"

Ein
1
const char someText[];
 ist also wirklich ein Text an exakt der Speicherstelle die durch den 
struct vorgegeben wird. Hier kann ich aus der Adresse des symbols 'a2' 
genau berechnen wo mein Text sich befindet.
Ein
1
const char* someText;
 ist dagegen ein Zeiger auf die Adresse wo mein Text vom compiler 
abgelegt wurde, und ich kann die Textadresse aus der Adresse des Symbols 
'a' nicht berechnen.

Im embedded Bereich will man solche structs oft in bestimmte 
Speicherbereiche legen und dann evtl. mit speziellen Tools direkt aus 
dem Flash herauslesen oder hineinschreiben. Das geht dann nur mit 'const 
char x[]'.

Ich gebe zu, dieses Beispiel ist etwas konstruiert. Ich werde leider 
damit sehr oft konfrontiert, weil bei uns in diesen Bereichen (in 
solchen structs) bestimmte Konfigurationen und/oder Versionsnummern 
liegen.

Ich denke das ist jetzt aber sehr off-topic, sorry.

-Foka

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Markus F. schrieb:
> Das kann doch der Konstruktor übernehmen:typedef struct t {
>     int someint;
>     const char *someTxt;
>     t(int someint, const char *someTxt) { this->someint = someint;
> this->someTxt = someTxt; }
> } MyTypeT;

Wenn Du nicht die gleichen Namen für die Membervariablen und die 
Argumente des Konstruktors verwenden würdest, könntest Du Dir die 
Dereferenzierung über den this-Pointer sparen.

Die in manchen Kreisen verpönte Notation, Membervariablen durch ein 
vorangestelltes m_ kenntlich zu machen, ist hier hilfreich:
1
typedef struct t {
2
    int m_someint;
3
    const char *m_someTxt;
4
    t(int someint, const char *someTxt) { m_someint = someint; m_someTxt = someTxt; }
5
} MyTypeT;

In C++ ist das typedef übrigens überflüssig, die Struktur/Klasse kann 
direkt über "t" angesprochen werden:
1
struct t {
2
    int m_someint;
3
    const char *m_someTxt;
4
    t(int someint, const char *someTxt) { m_someint = someint; m_someTxt = someTxt; }
5
};
6
7
t* eineInstanzVont = new t(1, "bla");
8
t eineandereinstanz(2, "laber");

von Fabian O. (xfr)


Lesenswert?

Rufus Τ. Firefly schrieb:
> Markus F. schrieb:
>> Das kann doch der Konstruktor übernehmen:typedef struct t {
>>     int someint;
>>     const char *someTxt;
>>     t(int someint, const char *someTxt) { this->someint = someint;
>> this->someTxt = someTxt; }
>> } MyTypeT;
>
> Wenn Du nicht die gleichen Namen für die Membervariablen und die
> Argumente des Konstruktors verwenden würdest, könntest Du Dir die
> Dereferenzierung über den this-Pointer sparen.

Oder man verwendet die Initialisierungsliste:
1
typedef struct t {
2
  int someint;
3
  const char *someTxt;
4
  t(int someint, const char *someTxt)
5
    : someint(someint), someTxt(someTxt) {}
6
} MyTypeT;

Bei nicht-trivialen Membern ist das auch effizienter, da man so gleich 
den richtigen Konstruktor aufrufen kann, anstatt erst den 
Default-Konstruktor und dann Copy-Assignment zu machen.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

Man kann ja auc mit Templates arbeiten:
1
template<size_t S>
2
struct MyTypeT
3
{
4
    int someInt;
5
    const char someTxt[S];
6
};
7
8
const MyTypeT<17> a {42, "geht doch in C++"};

Ich wüßte nur gerade keinen einfachen Weg, die Arraygröße automatisch 
berechnen zu lassen, statt sie explizit als Template-Parameter angeben 
zu müssen. Geht aber bestimmt irgendwie.

von Markus F. (mfro)


Lesenswert?

Ich persönlich mag's durchaus, "this" hingeschrieben zu haben, wenn ich 
auch "this" meine (schreib's also auch meist hin, wenn's gar nicht 
notwendig ist).


Die Problematik "fehlende flexible array member" lässt sich übrigens 
auch - wenig schön, aber immerhin - über ein template lösen:
1
#include <cstddef>
2
3
template <size_t N> struct t
4
{
5
    int someint;
6
    char somechar[N];
7
};
8
9
t<sizeof("so geht's")> s = { 22, "so geht's" };

Der Schönheit kann man mit einem Macro auf die Sprünge helfen.

von Rolf M. (rmagnus)


Lesenswert?

Markus F. schrieb:
> Der Schönheit kann man mit einem Macro auf die Sprünge helfen.

Naja, schön ist was anderes, aber gehen tut das natürlich.

von Michael (Gast)


Lesenswert?

Karl Heinz schrieb:
> Die Kleinigkeit, dass der Name einer Struktur automatisch ein eigener
> Datentyp wird (kein typedef erforderlich), ist ein nettes kleines C++
> Feature von dem man sich fragt, warum das in C nicht auch gleich so
> gemacht wurde.

Hat mich beispielsweise noch nie gestört. Ein typedef benutze ich 
höchstens für einen Funktionszeiger, weil mir die Syntax desselben als 
Parameter zu umständlich ist.

Aber für eine struct?
1
struct a
2
{
3
    unsigned char member;
4
};
5
6
void b(void)
7
{
8
    struct a local;
9
}

Was spricht hier gegen?

von Foka M. (foka)


Lesenswert?

Rolf Magnus schrieb:
> Man kann ja auc mit Templates arbeiten:
>
>
1
> template<size_t S>
2
> struct MyTypeT
3
> {
4
>     int someInt;
5
>     const char someTxt[S];
6
> };
7
> 
8
> const MyTypeT<17> a {42, "geht doch in C++"};
9
>
>
> Ich wüßte nur gerade keinen einfachen Weg, die Arraygröße automatisch
> berechnen zu lassen, statt sie explizit als Template-Parameter angeben
> zu müssen. Geht aber bestimmt irgendwie.

Dann werde ich wieder mal meckern ;-)
Das habe ich auch schon probiert und dachte ich habe endlich die 
Loesung gefunden. Naja... zumindest teilweise, weil wie gesagt: die 
Definition des structs liegt ja innerhlab von 3-rd party code (aber 
lassen wir das kurz bei Seite).

Bei dieser 'Loesung' wird fuer jede, unterschiedlich lange, Zeichenkette 
im Flash eine neue Tempalte-Instanz angelegt. Erstellt man also n 
Instanzen von
1
 const MyTypeT<X_n> a_n
dann fuellt sich die .text section schnell auf (natuerlich nur, wenn 
fuer jedes n das X_n unique ist).

Ganz klar, es ist schon mal viel besser, vor allem ist es C++. Doch 100% 
zufrieden war ich mit dieser Loesung auch nicht. So unglaublich 
praktisch wie Templates sind, muss man, IMHO besonders im 8-Bitter 
Kontext, aufpassen, denn das oben beschriebene Verhalten kann schneller 
auftraeten als man denkt. Ich habe mal nicht daran gedacht und musste es 
leidvoll erfahren...

-Foka

von Rolf M. (rmagnus)


Lesenswert?

Foka Mokra schrieb:
> Bei dieser 'Loesung' wird fuer jede, unterschiedlich lange, Zeichenkette
> im Flash eine neue Tempalte-Instanz angelegt.

Was sollte da denn im Flash erzeugt werden außer den Daten, die da ja so 
oder so liegen müssen? Das Template enthält doch gar keinen Code.

von Foka M. (foka)


Lesenswert?

Rolf Magnus schrieb:
> Foka Mokra schrieb:
>> Bei dieser 'Loesung' wird fuer jede, unterschiedlich lange, Zeichenkette
>> im Flash eine neue Tempalte-Instanz angelegt.
>
> Was sollte da denn im Flash erzeugt werden außer den Daten, die da ja so
> oder so liegen müssen? Das Template enthält doch gar keinen Code.

Stimmt Du hast natuerlich Recht.
So lange das template keine Funktionen enthalet, hat es keinen Einfluss 
auf die .text section.

Mein Fehler.

Ich hatte vergessen, dass ich damals in dem struct noch einige 
Memberfuktionen hatte, in etwa so:
1
#include <stdio.h>
2
3
template<int N>
4
struct Amen {
5
   int myInt;
6
   const char someText[N+1];
7
   void printme() const {
8
      printf("%s\n", someText);
9
   }
10
};
11
12
const Amen<1> a1 = { 1, "1" };
13
const Amen<2> a2 = { 2, "22" };
14
const Amen<3> a3 = { 3, "333" };
15
const Amen<4> a4 = { 4, "4444" };
16
const Amen<5> a5 = { 1, "55555" };
17
const Amen<6> a6 = { 1, "666666" };
18
19
void printme(){
20
   a1.printme();
21
   a2.printme();
22
   a3.printme();
23
   a4.printme();
24
   a5.printme();
25
   a6.printme();
26
}
27
28
int main(){
29
   printme();
30
   return 0;
31
}

nach einem: avr-g++ -Wl,--Map=a.map tt.cpp
enthalet das map file folgendes:
1
 *(.text.*)
2
 .text._ZNK4AmenILi1EE7printmeEv
3
                0x000000000000006e       0x20 tt.o
4
                0x000000000000006e                _ZNK4AmenILi1EE7printmeEv
5
 .text._ZNK4AmenILi2EE7printmeEv
6
                0x000000000000008e       0x20 tt.o
7
                0x000000000000008e                _ZNK4AmenILi2EE7printmeEv
8
 .text._ZNK4AmenILi3EE7printmeEv
9
                0x00000000000000ae       0x20 tt.o
10
                0x00000000000000ae                _ZNK4AmenILi3EE7printmeEv
11
 .text._ZNK4AmenILi4EE7printmeEv
12
                0x00000000000000ce       0x20 tt.o
13
                0x00000000000000ce                _ZNK4AmenILi4EE7printmeEv
14
 .text._ZNK4AmenILi5EE7printmeEv
15
                0x00000000000000ee       0x20 tt.o
16
                0x00000000000000ee                _ZNK4AmenILi5EE7printmeEv
17
 .text._ZNK4AmenILi6EE7printmeEv
18
                0x000000000000010e       0x20 tt.o
19
                0x000000000000010e                _ZNK4AmenILi6EE7printmeEv

... und ich habe mich gewundert warum mein Code, wegen paar Variablen, 
enormen flash-Verbrauch hatte :-O

-Foka

von Vlad T. (vlad_tepesch)


Lesenswert?

Osterhase schrieb:
> Das Problem ist, dass someTxt[] kein Array, sondern ein Pointer ist. Es
> ist eine andere Schreibweise für: const char *someTxt;

das ist es nicht.

Foka Mokra schrieb:
> Ich hatte vergessen, dass ich damals in dem struct noch einige
> Memberfuktionen hatte, in etwa so:

dann pack die funktionen in die Basisklasse und mach die Ableitung mit 
den Stringmember. NAchteil ist du brauchst eine virtuelle Funktion, die 
die Daten liefert und doch wieder in jeder Klasse enhalten ist.
Aber die großen Funktionen sind wenigstens nur einmal enthalten.

also in etwa:
1
struct Base{
2
   virtual const char* getText() const = 0;
3
   int myInt;
4
   void printme() const {
5
      printf("%s\n", getText());
6
   }
7
8
};
9
10
template<int N>
11
struct Amen: public Base {
12
   const char someText[N+1];
13
   virtual const char* getText() const {return someText;};
14
   
15
};
(nicht getestet, nur ne idee - weiß nicht, ob die Aggregatinitialisierer 
hier noch funktionieren)

: Bearbeitet durch User
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.