Forum: Mikrocontroller und Digitale Elektronik uint32 Array in uint8 Array wandeln


von Seppel (Gast)


Lesenswert?

Hallo,

wie wandle ich am besten ein uin32 Array in ein uint8 Array am 
effizientesten (Kein Pfusch ;-) ).

Klar kann ich so was verwenden, aber vielleicht hat jemand noch andere 
gute Ideen.
1
uint8_t arr[24];
2
uint32_t Tx_PP[6];
3
arr[0]=(Tx_PP[0] >> 24) & 0xFF;
4
arr[1]=(Tx_PP[0] >> 16) & 0xFF;
5
arr[2]=(Tx_PP[0] >> 8) & 0xFF;
6
arr[3]=(Tx_PP)[0] & 0xFF;

Vielen Dank, Grüße, Seppel

Quelle: 
https://electronics.stackexchange.com/questions/523334/how-to-split-uint32-into-four-uint8-in-efr32

[Mod: c-Tags eingesetzt, beim nächsten Mal bitte selber machen]

: Bearbeitet durch Moderator
von Harry L. (mysth)


Lesenswert?


von Seppel (Gast)


Lesenswert?

Harry L. schrieb:
> https://www.learn-c.org/de/Unions

Das ist undefigned, wegen dem Alignement, oder? Bei Embedded habe ich 
ewig keine Unions gesehen, ...

von A. S. (Gast)


Lesenswert?

Was möchtest Du denn machen? Oder was willst Du optimieren?


Viele Konstrukte setzt Dein Compiler bei höchste Optimierung in wenige 
oder 1 Assemblerzeile um. Genauso gut kann er aber auch daran 
verzweifeln, weil ihm irgendwas nicht passt.

Und ja, manche nehmen memcpy, unions oder was auch immer und sichern 
dass mit ein paar asserts oder Randbedingungen ab. Sauber ist das nicht 
immer, aber oft schneller oder pragmatischer, wenn ich z.B. nur einen 
pointercast brauche.

von PittyJ (Gast)


Lesenswert?

Wenn du es portabel halten möchtest, dann ist die jetzige Lösung wohl 
das geeigete. Bei allem anderem musst du den Prozessor kennen.

Von TI gibt es z.B. noch eine DSP Serie, die ist nur 16 bittig, d.h. 
auch ein uint8_t und ein Byte besteht aus 16 Bit. Und wenn du so eine 
CPU benutzt, dann sind sämtliche Unions etc nicht mehr möglich. Das 
portable Konstrukt funktioniert aber weiterhin.

von Wilhelm M. (wimalopaan)


Lesenswert?

Weil es nicht zu erkennen ist, ob C oder C++:

- in C ist type-punning per union explizit ok.
- in C ist type-punning per pointer-cast auch UB wegen strict-aliasing
- in C++ ist type-punning per union immer UB.

Und: type-punning per union ist auch gar nicht notwendig, denn Deine 
Lösung ist die richtige und nicht aufwändiger als per union.

von MaWin (Gast)


Lesenswert?

Wilhelm M. schrieb:
> - in C ist type-punning per union explizit ok.

Wäre mir neu. Ist das in einem neuen C-Standard aufgenommen worden?

> - in C ist type-punning per pointer-cast auch UB wegen strict-aliasing

Für uint8_t*/char* (also für genau diesen Fall hier) ist es nicht UB.

von Seppel (Gast)


Lesenswert?

Hallo,

was ist denn "UB"?

Grüße, Seppel

von Ergo70 (Gast)


Lesenswert?

Undefined behavior vermutlich

von jojo (Gast)


Lesenswert?

MaWin schrieb:
> Wäre mir neu. Ist das in einem neuen C-Standard aufgenommen worden?

Ja. https://stackoverflow.com/a/25672839

@OP, deine Lösung ist korrekt und die portabelste, solltest du es doch 
mal mit nem C++ compiler bauen wollen. Verpacks in eine inline Funktion 
oder ein makro und gut ist.

Ergo70 schrieb:
> Undefined behavior vermutlich

korrekt, UB = undefined behavior. D.h. kann gut gehen, tut es aber nicht 
unter allen Bedingungen. Nicht schön. Auf jeden Fall vermeiden

von Huch (Gast)


Lesenswert?

jojo schrieb:
> @OP, deine Lösung ist korrekt und die portabelste, solltest du es doch
> mal mit nem C++ compiler bauen wollen. Verpacks in eine inline Funktion
> oder ein makro und gut ist.

Ich bin etwas erstaunt/erschrocken, dass (std::)memcpy noch nicht 
genannt wurde. DAS ist die portable Methode in C++ und auch C, und wird 
ohnehin weboptimiert.

Seppel schrieb:
> Harry L. schrieb:
>> https://www.learn-c.org/de/Unions
>
> Das ist undefigned, wegen dem Alignement, oder? Bei Embedded habe ich
> ewig keine Unions gesehen, ...

Nein, weil das größte alignment der member für den ganzen union zählt. 
Somit gibt es kein Alignmentproblem.
1
// works for C and C++
2
3
#ifdef __STDC__
4
# include <stdint.h>
5
#else
6
# include <cstdint>
7
#endif
8
9
#ifdef __STDC__
10
# include <assert.h>
11
# include <stdalign.h>
12
#endif
13
14
typedef union {
15
    uint8_t i[24];
16
} A;
17
18
typedef union {
19
    uint8_t i[24];
20
    uint64_t j[3];
21
} B;
22
23
static_assert(sizeof(A) == sizeof(B));
24
static_assert(alignof(A) == 1);
25
static_assert(alignof(B) == 8);

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Huch schrieb:
> Ich bin etwas erstaunt/erschrocken, dass (std::)memcpy noch nicht
> genannt wurde. DAS ist die portable Methode in C++ und auch C, und wird
> ohnehin weboptimiert.

Es ist zwar legal, aber das Ergebnis ist trotzdem plattformabhängig und 
damit nicht besonders portabel. Was am Ende in "arr" steht hängt von der 
Byte-Reihenfolge ab. Die Original-Lösung mit Bitshifts hingegen ist 
portabel, denn da ist das Ergebnis immer gleich.

Ich hatte das mal hier alles zusammengefasst: Serialisierung

von Harry L. (mysth)


Lesenswert?

Seppel schrieb:
> Harry L. schrieb:
>> https://www.learn-c.org/de/Unions
>
> Das ist undefigned, wegen dem Alignement, oder?
Nein!
Siehe auch: Beitrag "Re: uint32 Array in uint8 Array wandeln"

> Bei Embedded habe ich ewig keine Unions gesehen, ...

Wohl weil die meisten "Maker" kein C können...

: Bearbeitet durch User
von PittyJ (Gast)


Lesenswert?

Niklas G. schrieb:
> Es ist zwar legal, aber das Ergebnis ist trotzdem plattformabhängig und
> damit nicht besonders portabel. Was am Ende in "arr" steht hängt von der
> Byte-Reihenfolge ab. Die Original-Lösung mit Bitshifts hingegen ist
> portabel, denn da ist das Ergebnis immer gleich.
>
> Ich hatte das mal hier alles zusammengefasst: Serialisierung

Ganz meine Meinung!
Die portable Lösung nehmen, den Rest optimiert eh der Compiler. Da merkt 
man keinen Geschwindigkeitsunterschied. Ausser, das Programm macht 
einzig diese Konvertierungen und nichts anderes.

von Εrnst B. (ernst)


Lesenswert?

PittyJ schrieb:
> den Rest optimiert eh der Compiler.

Für amd64 macht der GCC aus dem Codeschnipsel im Eröffnungspost genau 
drei ASM-Anweisungen:
1
        mov     eax, DWORD PTR Tx_PP[rip]
2
        bswap   eax
3
        mov     DWORD PTR arr[rip], eax
für ARM in etwa dasselbe.

interessanter ist, was für 8-Bit-Architekturen dabei rauskommt, oder auf 
BigEndian-Maschinen, oder für eine Schleife über ein größeres Array, die 
sich evtl. per AVX&co weiter optimieren ließe...

von Steve van de Grens (roehrmond)


Lesenswert?

Huch schrieb:
> Ich bin etwas erstaunt/erschrocken, dass (std::)memcpy noch nicht
> genannt wurde.

Wurde 20 Stunden vorher genannt:

A. S. schrieb:
> Und ja, manche nehmen memcpy, unions oder was auch immer

Huch schrieb:
> DAS (memcpy) ist die portable Methode in C++ und auch C,
> und wird ohnehin weboptimiert.

Ich denke nicht, denn memcpy ordnet die Reihenfolge der Bytes ebenso 
wenig um, wie unions.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

MaWin schrieb:
> Wilhelm M. schrieb:
>> - in C ist type-punning per union explizit ok.
>
> Wäre mir neu. Ist das in einem neuen C-Standard aufgenommen worden?

Naja, so arg neu ist das nicht. Es wurde mit C99 aufgenommen, also vor 
23 Jahren.
Ich finde unions dafür aber trotzdem wenig geeignet. Sie sind eigentlich 
dafür nicht gedacht, und ich finde es auch umständlich, extra nur für 
die Umwandlung einen neuen Datentyp definieren zu müssen.
Ja nachdem, ob es einfach oder portabel sein soll, würde ich entweder 
die memcpy-Variante oder die mit den Shifts verwenden.

von udok (Gast)


Lesenswert?

Die memcpy Variante funktioniert nur mit den drei großen Compilern, und 
auch nur wenn die Kommandozeilenparameter passen.
UB sind alle Varianten wegen Bitreihenfolge. Das &0xff ist überflüssig, 
wenn man gerne viel schreibt, kann man explizit casten.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

udok schrieb:
> Die memcpy Variante funktioniert nur mit den drei großen Compilern, und
> auch nur wenn die Kommandozeilenparameter passen.

Nein, der Standard schreibt vor dass das funktionieren muss. Daher 
können alle Compiler das. Lediglich das Ergebnis ist plattform-abhängig 
(IB).

udok schrieb:
> UB sind alle Varianten wegen Bitreihenfolge.

Wenn schon Bytereihenfolge, und es ist IB, nicht UB.

von udok (Gast)


Lesenswert?

Niklas G. schrieb:
> Nein, der Standard schreibt vor dass das funktionieren muss. Daher
> können alle Compiler das. L

Funktionieren tut es ja auch, langsam halt.

von udok (Gast)


Lesenswert?

Niklas G. schrieb:
>> UB sind alle Varianten wegen Bitreihenfolge.
>
> Wenn schon Bytereihenfolge, und es ist IB, nicht UB.

Klugscheißer?

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

udok schrieb:
> Funktionieren tut es ja auch, langsam halt.

Nicht unbedingt, wenn die Variablen lokal sind können Compiler das gut 
wegoptimieren. Ganz sicher dass das nur die drei großen können?

udok schrieb:
> Klugscheißer?

Das ist sin signifikanter Unterschied.

: Bearbeitet durch User
von HildeK (Gast)


Lesenswert?

Rolf M. schrieb:
> Ja nachdem, ob es einfach oder portabel sein soll, würde ich entweder
> die memcpy-Variante oder die mit den Shifts verwenden.

Ich bin kein SW-Guru, haut mich also nicht 😀.
Ich hätte das mit einem uint8_t-Pointer auf das uint32_t Array versucht. 
Das müsste doch genauso funktionieren wie ein union-Konstrukt?
Natürlich mit den selben Einschränkungen bez. der Byteorder und ggf. der 
Portierbarkeit.

Bezüglich Portierbarkeit: oft hat man genau eine Umgebung, einen 
Compiler und eine Plattform. Dann braucht die Portierbarkeit nicht 
zwingend eine wichtige Randbedingung sein, wenn es in der Umgebung den 
Zweck erfüllt. Ein Kommentar diesbezüglich im Quelltext wäre sicher 
nicht falsch!

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

HildeK schrieb:
> Ich hätte das mit einem uint8_t-Pointer auf das uint32_t Array versucht.
> Das müsste doch genauso funktionieren wie ein union-Konstrukt?

In C ist es identisch, in C++ ist es sogar besser als die union, denn 
wie schon geschrieben ist die Verwendung von union's auf diese Art in 
C++ fehlerhaft. Im Endeffekt ist es aber exakt das Gleiche wie memcpy(), 
denn das benutzt "nominell" einen char-Pointer.

HildeK schrieb:
> Bezüglich Portierbarkeit: oft hat man genau eine Umgebung, einen
> Compiler und eine Plattform. Dann braucht die Portierbarkeit nicht
> zwingend eine wichtige Randbedingung sein

Das haben sich schon viele gedacht. Dann kam AMD64 um die Ecke. Und dann 
ARM. Und dann ARM64... Gerade wenn man die korrekte Variante mit den 
Bitshifts schon da hat muss man ja nicht auf was weniger portables 
wechseln?

von HildeK (Gast)


Lesenswert?

Niklas G. schrieb:
> Im Endeffekt ist es aber exakt das Gleiche wie memcpy(),
> denn das benutzt "nominell" einen char-Pointer.

Ich hatte gedacht, dass memcpy() eine echte Kopie erstellt, also zweimal 
den Speicherplatz benötigt.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

HildeK schrieb:
> Ich hatte gedacht, dass memcpy() eine echte Kopie erstellt, also zweimal
> den Speicherplatz benötigt.

Wie gesagt, nicht unbedingt wenn es um lokale Variablen geht. Dann wird 
das gern mal wegoptimiert.

von Andreas M. (amesser)


Lesenswert?

Εrnst B. schrieb:
> Für amd64 macht der GCC aus dem Codeschnipsel im Eröffnungspost genau
> drei ASM-Anweisungen:

Und das auch nur, weil der Codeschnipsel vom Anfang nämlich implizit 
auch noch eine Konvertierung nach Big-Endian macht. (im uint8_t array 
sind die Daten in Big-Endian abgelegt, und zwar immer, unabhängig von 
der Byteorder der CPU). Sonst wären es sogar nur zwei Anweisungen.

Deswegen sind alle Vorschläge mit memcpy hier sogar komplett falsch...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Andreas M. schrieb:
> Deswegen sind alle Vorschläge mit memcpy hier sogar komplett falsch...

Naja, Seppel hat nicht gesagt auf welcher Plattform er arbeitet. Wenn er 
auf einer Big Endian Plattform arbeitet, wäre memcpy identisch. Aber 
eben nicht portabel auf Little Endian Plattformen...

von DPA (Gast)


Lesenswert?

Ich würde auf jeden fall die Bitshifts nehmen. Das kann man auch in eine 
Funktion packen. Wird alles wegoptimiert. 
https://godbolt.org/z/MGjYEKzWc

Auf godbolt.org kann man auch verschiedene Compiler ausprobieren. Jeder 
dort kriegt das wegoptimieren hin. Naja, fast, msvc zum Beispiel schafft 
es nicht einmal, den Code zu kompilieren. MS hat es also immernoch nicht 
geschafft, einen funktionierenden C Compiler zu machen...
1
#include <stdint.h>
2
#include <stdio.h>
3
4
static inline void u32_u8_be(uint8_t x[static const restrict 4], uint32_t u){
5
  x[0] = u >> 24;
6
  x[1] = u >> 16;
7
  x[2] = u >>  8;
8
  x[3] = u;
9
}
10
11
int main(){
12
  uint8_t x[5] = {0};
13
  u32_u8_be(x, 0x6d656f77);
14
  puts((char*)x);
15
  return 0;
16
}

Das Ursprüngliche Beispiel des TO war übrigens auch Big Endian, und all 
die anderen hier haben nun host byte order, auf den meisten Rechnern 
little endian, Beispiele gebracht.

von Wilhelm M. (wimalopaan)


Lesenswert?

HildeK schrieb:
> Ein Kommentar diesbezüglich im Quelltext wäre sicher
> nicht falsch!

Echt jetzt?

von Michael D. (nospam2000)


Lesenswert?

Wilhelm M. schrieb:
> HildeK schrieb:
>> Ein Kommentar diesbezüglich im Quelltext wäre sicher
>> nicht falsch!
>
> Echt jetzt?

Klar doch, dann kann man nachdem man den bug gefunden hat ganz klar 
sehen, welcher Autor das bewusst unportabel programmiert hat und ihm in 
den Hintern treten oder ihm kündigen.

  Michael

von A. S. (Gast)


Lesenswert?

HildeK schrieb:
> Ein Kommentar diesbezüglich im Quelltext wäre sicher
> nicht falsch!

A. S. schrieb:
> manche [...] sichern dass mit ein paar asserts oder Randbedingungen ab.
> Sauber ist das nicht immer, aber oft schneller oder pragmatischer,
> wenn ich z.B. nur einen pointercast brauche.

Es gibt verschiedene Möglichkeiten, Alignment oder Endianess zur 
Compilezeit oder spätestens zur Laufzeit zu prüfen. Das ist m.E. einem 
Kommentar vorzuziehen.

von HildeK (Gast)


Lesenswert?

Michael D. schrieb:
> Wilhelm M. schrieb:
>> HildeK schrieb:
>>> Ein Kommentar diesbezüglich im Quelltext wäre sicher
>>> nicht falsch!
>>
>> Echt jetzt?
>
> Klar doch, dann kann man nachdem man den bug gefunden hat ganz klar
> sehen, welcher Autor das bewusst unportabel programmiert hat und ihm in
> den Hintern treten oder ihm kündigen.

Ich hatte extra darum gebeten, mich nicht zu hauen 😀.
Wenn ich mal Software schreibe, ist die für mich selber. Ich bin kein 
Softwareentwickler und verwende die µCs im Wesentlichen deshalb, weil 
ich damit kleiner Projekte mit minimalem HW-Aufwand flexibel durchführen 
kann. Mich kann auch niemand mehr kündigen. Und meine Plattform und 
Umgebung ist über Jahre gleich geblieben. Da reicht für mich selber 
tatsächlich ein diesbezüglicher Kommentar für den unwahrscheinlichen 
Fall, dass ich das Schnipsel möglicherweise mal wo ganz anders 
wiederverwenden will.
Nur unter den Bedingungen wollte ich das verstanden wissen ...

Niklas G. schrieb:
> Wie gesagt, nicht unbedingt wenn es um lokale Variablen geht. Dann wird
> das gern mal wegoptimiert.

Danke für die Info. Ich hatte das so nicht auf dem Schirm. Sobald aber 
mal ein Array statisch oder global angelegt wird, dürfte das nicht mehr 
der Fall sein.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

HildeK schrieb:
> Ich hatte extra darum gebeten, mich nicht zu hauen 😀.
> Wenn ich mal Software schreibe, ist die für mich selber.

Macht es dann Sinn suboptimale Vorschläge zu machen, wenn bereits im 
Ausgangsposting die korrekte Lösung steht, die auch schon von Experten 
bestätigt wurde?

von HildeK (Gast)


Lesenswert?

Es ging darum, welche Möglichkeiten es noch geben könnte. Dass solche 
mit den ggf. damit verbundenen Nachteilen diskutiert werden, ist doch 
nicht falsch?

von Rolf M. (rmagnus)


Lesenswert?

HildeK schrieb:
> Rolf M. schrieb:
>> Ja nachdem, ob es einfach oder portabel sein soll, würde ich entweder
>> die memcpy-Variante oder die mit den Shifts verwenden.
>
> Ich bin kein SW-Guru, haut mich also nicht 😀.
> Ich hätte das mit einem uint8_t-Pointer auf das uint32_t Array versucht.

Und dann? Nehme ich diesen Pointer, um per for-Schleife den Inhalt ins 
Zielarray zu kopieren? Welchen Vorteil sollte das gegenüber memcpy 
haben?

> Das müsste doch genauso funktionieren wie ein union-Konstrukt?

Bei der union kopiere ich es sogar zweimal: Einmal von der Quelle in die 
union und einmal von der union ins Zielarray.
Wobei ein vernünftiger Compiler am Ende aus allen Varianten den selben 
oder zumindest gleichwertigen Code generiert.

> Bezüglich Portierbarkeit: oft hat man genau eine Umgebung, einen
> Compiler und eine Plattform. Dann braucht die Portierbarkeit nicht
> zwingend eine wichtige Randbedingung sein, wenn es in der Umgebung den
> Zweck erfüllt.

Meine Erfahrung aus fast 30 Jahren Programmierung: Wenn der Aufwand für 
die portable Lösung nicht signifikant größer ist als für die unportable, 
dann ist es sinnvoll, erstere umzusetzen.
Oft genug wird aber das Thema Portabilität anfangs komplett ignoriert, 
und wenn es dann später doch mal portiert werden soll, hat man einen 
riesigen Aufwand, der erheblich kleiner hätte sein können, ohne vorher 
großartig mehr Aufwand reingesteckt zu haben. Deshalb achte ich immer 
von Anfang an darauf, Dinge höchstens dann unportabel zu machen, wenn 
sie an der Stelle für mich einen signifikanten Vorteil gegenüber der 
portablen Variante haben.

> Ein Kommentar diesbezüglich im Quelltext wäre sicher nicht falsch!

Besser dann ein paar asserts, die fehlschlagen, wenn die getroffenen 
Annahmen über das System nicht zutreffen.

von HildeK (Gast)


Lesenswert?

Rolf M. schrieb:
> Und dann? Nehme ich diesen Pointer, um per for-Schleife den Inhalt ins
> Zielarray zu kopieren? Welchen Vorteil sollte das gegenüber memcpy
> haben?

Nein, nicht kopieren. Ich dachte an den Zugriff auf die einzelnen Bytes 
des uint32_t-Arrays. Keine Kopie erstellen, denn dann natürlich memcpy.
So in der Art:
1
int main(void) {
2
  int i;
3
  uint32_t var32[10] = {11,20,300,4000,50000,125,7463,554321,0x1FFFFFF2,5};
4
  uint8_t *var8;
5
  var8 = (uint8_t*) var32;
6
7
    for (i=0; i<40; i++)
8
    {
9
      printf ("%X  ", var8[i]);
10
    }
11
}
Aber es ist nicht ganz das, was der TO wollte - er wollte ein zweites 
Array.

von DerEgon (Gast)


Lesenswert?

HildeK schrieb:
> for (i=0; i<40; i++)

Statt "40" würde ich da "sizeof var32" hinschreiben.

von Εrnst B. (ernst)


Lesenswert?

HildeK schrieb:

>       printf ("%X  ", var8[i]);

und mit

printf ("%02X ", var8[(i&~3)+3-(i&3)]);

Kommt auch die Byteorder wie vom TE gewünscht raus.

von HildeK (Gast)


Lesenswert?

@DerEgon und @Ernst B.
Mir ging es nur darum, zu verdeutlichen, was ich ganz oben meinte.
Danke für die Ergänzungen!
Wobei: auf var8[(i&~3)+3-(i&3)] wäre ich nicht gekommen, ich verstehe 
nicht mal, wie es funktioniert, aber es tut 😀.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Εrnst B. schrieb:
> Kommt auch die Byteorder wie vom TE gewünscht raus.

Naja, es kommt die umgekehrte Reihenfolge vom Host raus. Wenn der TE von 
Big Endian ausgeht, kommt Little Endian raus, also genau falsch.

von Εrnst B. (ernst)


Lesenswert?

Niklas G. schrieb:
> Naja, es kommt die umgekehrte Reihenfolge vom Host raus. Wenn der TE von
> Big Endian ausgeht, kommt Little Endian raus, also genau falsch.

Stimmt natürlich.

HildeK schrieb:
> Wobei: auf var8[(i&~3)+3-(i&3)] wäre ich nicht gekommen, ich verstehe
> nicht mal, wie es funktioniert, aber es tut 😀.

Es verwurschtelt die zwei niedrigsten Bits in der Adresse (& 3 
entspricht & 0b011), damit diese "rückwärts" zählen.
Erzeugt dabei aber vmtl. furchtbar ineffizienten ASM-Code.

von HildeK (Gast)


Lesenswert?

Niklas G. schrieb:
> Naja, es kommt die umgekehrte Reihenfolge vom Host raus. Wenn der TE von
> Big Endian ausgeht, kommt Little Endian raus, also genau falsch.

Richtig. Er hat es vermutlich auf meinen Ausschnitt bezogen und da kommt 
es mit meiner PC-Umgebung dann beginnend mit dem MSByte richtig rum 
heraus.
Plattform abhängig bleibt es, da hilft nur der vom TO schon im 
Eröffnungspost angegebene Variante.

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.