kann mir vielleicht hier jemand kurz und prägnant, am besten an einem kleinen beispiel, erklären, was volatile vor variablen bedeutet? besten dank!
volatile .. flüchtig naja.. eine als volatile deklarierte variable muss vom kompiler vor jeder verwendung aus dem sram geladen werden, kann nicht in registern gehalten werden und wird nur verwendet für variablen die in einer isr den wert verändern können oder um davor zu schützen, dass der kompiler optimiert: int bla, rum; volatile int schnaps; for( bla = 0; bla < 255; bla++ ); // wird vom kompiler wegoptimiert! for( bla = 0; bla < 255; bla++ ) rum = schnaps; -> wird nicht wegoptimiert. also 255 mal durchlaufen und nicht nur 1x
for( bla = 0; bla < 255; bla++ ) rum = schnaps; Das mit der Optimierung ist aber nur ein Nebeneffekt und keineswegs der Sinn von volatile-Variablen! Deren Sinn ist, sicherzustellen, daß eine Variable, deren Wert sich asynchron ändern kann (durch eine ISR oder einen anderen Thread, oder Prozeß), vor Gebrauch immer aus dem Speicher nachgeladen und nie als temporäre Kopie in einem Register gehalten wird.
Wobei man sich darauf auch nicht 100%ig verlassen kann, Operationen auf volatile sind auch net atomar (bei CISC häufig, bei RISC fast immer), sprich während der Operation kann auch mal ein Interrupt auftauchen der die noch verändert. Bei RISC können schon so einfache Sachen wie "volatile int a; [...] a+=1;" schiefgehen (bei CISC natürlich auch), desswegen Interrupts vorher ausstellen.
I_ H. wrote: > Wobei man sich darauf auch nicht 100%ig verlassen kann, Operationen auf > volatile sind auch net atomar (bei CISC häufig, bei RISC fast immer), > sprich während der Operation kann auch mal ein Interrupt auftauchen der > die noch verändert. > Bei RISC können schon so einfache Sachen wie "volatile int a; [...] > a+=1;" schiefgehen (bei CISC natürlich auch), desswegen Interrupts > vorher ausstellen. Das hat damit auch überhaupt nichts zu tun. Für die Atomarität muss der Programmierer trotz volatile noch sorgen.
Schon klar, ging nur darum, dass
>Deren Sinn ist, sicherzustellen, daß eine Variable, deren Wert sich
asynchron ändern kann (durch eine ISR oder einen anderen Thread, oder
Prozeß), vor Gebrauch immer aus dem Speicher nachgeladen und nie als
temporäre Kopie in einem Register gehalten wird.<
eben nicht bedeutet, dass es ausreicht eine Variable als volatile zu
deklarieren, damit der Code nachvollziehbares tut (bzw. den
Programmierer nicht in den Wahnsinn treibt).
Wenn immer jeder (und auch alle die den Thread lesen) genau das herauslesen würde, was gemeint war, gäbe es keine Missverständnisse und keine Kriege mehr. Es stand nicht explizit da, desswegen hab ich es nochmal explizit hingeschrieben.
Naja, ich denke man muss es im Umfeld sehen. Wer noch nicht mal volatile kennt wird erst recht nicht wissen das er für den atomaren Zugriff selber sorgen muss. Von daher finde ich die Anmerkung dazu schon richtig aber vor allem auch sehr wichtig (verhindert dann auch weitere Post weil irgendwelche "zufälligen" Fehler im Programmablauf auftreten ;) PP
Sorry, dass ich den Thread nochmals hervorhole, aber was meint man mit atomar, ich habe das auch mit den Erklärungen im Netz nicht verstanden. und wieso macht macht man Variablen volatile, wenn sie sich ändern können. das kann man ja mit einer normalen Variable auch, nämlich durch Pointer. Dann hat sich der Wert der Variable ja auch geändert. Und das könnte ich ja genauso in einem Interrupt machen, wenn ich es bräuchte. Wieso also volatile? Ich verstehe irgendwie immer noch nicht wieso man volatile benötigt.
Wenn eine Variable von einer Funktion in Registern gehalten werden kann, dann kann sie auch in 2 Funktionen in Registern gehalten werden. Eigentlich nichts schlimmes dran, weil der Kompiler das weiß, und richtig abhandelt. Aber: Wird die Variable in einem Registersatz verändert, sieht der andere nichts davon. Das tritt bei Interrupts auf. Der Compiler kann nicht wissen, wann ein solcher eintritt. Wenn man den Effekt unterdrücken will, macht man die Variable volatile.
Hallo, eine meinetwegen globale Variable die in einer ISR verändert wird, deklariert/definiert man mit volatile. Soweit klar. Jetzt möchte man irgendwann im Code den Wert dieser Variable wissen. Nun muss man dafür sorge das während des Zugriffs der Wert der Variable nicht verändert wird. Deswegen greift man im atomaren "Schutzzustand" darauf zu. Das heißt nichts änderes als das die Interrupts kontrolliert gesperrt und danach wieder kontrolliert freigegeben werden. SREG wird gesichert. Bei 1Byte Variablen braucht man das nicht. Ab 2Byte Variablen muss man das machen. Sonst kann es sein man greift auf das erste Byte zu, während dessen verändert sich der Wert in der ISR und dann greift man auf das 2.Byte zu. Dumm nur das beide Bytes die man dann hat nichts mehr miteinander zu tun haben. Dafür gibts eine Standard atomar Lib mit entsprechenden Funktionen.
volatile: Bei nicht-volatile Variablen geht der Compiler davon aus, dass er die Controlle darüber hat. Er kann dann ganz anders optimieren. atomar: Manche Variablen bestehen aus mehr Elemente, als bei einem Schreibzugriff geändert werden kann. (zB 32-Bit Variablen auf einem 8-Bit Rechner) Zwischen diesen Schreibzugriffen kann der Prozessor aber durch einen Interupt unterbrochen werden. Dann stehen teilweise noch alte Daten in der Variable Beispiel Variable hat 4711, neuer Wert soll 0815 sein (vier Stellen werden geschrieben). Mittendrin kommt ein Interrupt, dann steht da 0811. Wenn diese Variable in der Interruptroutine wichtig ist, gibt das ein Problem.
Die Antworten könnte man aus meiner Sicht tatsächlich prägnanter formulieren. Die Prägnanz ist hier notwendig, weil die Ursache, deren Wirkung mit "volatile" verhindert werden soll, die selbe sein kann, aber nicht prinzipiell die selbe ist wie in dem Fall, in dem man von "atomar" bzw. "nicht-atomar" spricht. In Kürze: Volatile - Dem Compiler wird mitgeteilt, dass der Wert der Variablen sich unabhängig von dem Programmfluss an und um eine gegebene Stelle herum verändern kann. Umgekehrt: Die Variable kann, obwohl das aus dem Programmtext so nicht hervorgeht, einen anderen Wert als erwartet haben. atomar - Eine Variable ist so groß (oder im Speicher oder einem Register so gestaltet), dass sie nicht als ganzes mit einer Maschinenoperation geholt, manipuliert oder gespeichert werden kann. Was nun bei den Erklärungen oft ein Problem ist, ist das viele Beispiele von Fällen in denen diese Gesichtspunkte wichtig sind, sich auf Interrupts beziehen. Dabei bekommt man leicht den Eindruck, dass Interrupts immer das Problem sind; und das alleinige Problem. Das ist aber nicht so. Es gibt zwei Fälle, in denen sich Variableninhalte, wie oben erwähnt, unabhängig vom Programmfluss verändern können. Der erste sind tatsächlich Interrupts und zwar präzise Variablen deren Inhalt innerhalb der Interrupt-Service-Routine verändert werden (können). Der zweite Fall sind Peripherieregister die etwa über Portpins ihren Inhalt verändern, weil ja diese äusseren Ereignisse, die diese Veränderung bewirken nicht im Programmfluss beschrieben sind. Man beachte , dass in diesem zweiten Fall eventuelle Interrupts nicht das Problem verursachen! In beiden Fällen, kann und muss dem Compiler mit "volatile" gesagt werden: "Verlass Dich nicht darauf, dass der Variableninhalt bei der Ausführung des Programms noch derselbe ist, wie beim letzen Mal, als diese Stelle im Code ausgeführt wurde. Also: Falls Du (Compiler) an diese Stelle kommst, lade den Variableninhalt (den Inhalt des Peripherieregister oder ähnliches) noch einmal in ein Register und verwende nicht den alten Registerinhalt." Was nun die Atomarität betrifft, liegt hier der Fall anders, insofern als Interrupts in handelsüblichen Prozessoren üblicherweise die einzige Problemquelle sind. Allgemein gilt, dass jede Unterbrechung des Programmflusses, das Problem der Atomarität verursacht. Nur gibt es eben im Laden fast nur Prozessoren bei denen allein Interrupts den Programmfluss unterbrechen. Nimmt man den Fall, das eine CPU nur Befehle zum Laden (speichern etc.) von 8-Bit-Werten hat und es ist nun ein 16-Bit Wert zu laden, so kann also ein Interrupt genau zwischen den beiden Befehlen, die jeweils einen Teil der 16-Bit laden auftreten. In der Zeit aber, in der der Interrupt verarbeitet wird, kann sich der noch nicht geladene Teil der Variablen ändern. Die Veränderung kann, muss aber nicht mit dem Ereignis zu tun haben, das den Interrupt ausgelöst hat. Der Interrupt kann beispielsweise ein Timer-Interrupt sein, die fragliche Variable aber ein Datenregister einer Kommunikationsschnittstelle. Um zu dem Einwand mit dem Zeiger (Pointer) zu kommen: Die Anwendung von Zeigern, verhindert das Problem nicht. Leider ist der Einwand: "das kann man ja mit einer normalen Variable auch, nämlich durch Pointer. Dann hat sich der Wert der Variable ja auch geändert. Und das könnte ich ja genauso in einem Interrupt machen, wenn ich es bräuchte. Wieso also volatile?" aus meiner Sicht nicht klar formuliert. Meine Fragen wären: "Was kann man mit einer normalen Variablen auch"? "Wann hat sich der Wert der Variablen auch geändert"? "Was kann ich ja genauso in einem Interrupt machen, wenn ich es brauche"? - Kurz: Falls das ein Beispiel sein sollte, wie man es mit Zeigern machen könnte enthält es zu wenig Details. Aber wenn ich mal versuche, den Einwand zu interpretieren, dann scheint er auf dem Gedanken zu beruhen, dass ein Zeiger ja trotz eines evtl. Interrupts konstant bleibt. Daher ist scheinbar kein "volatile" notwendig. Aber das ist falsch. Das Problem ist, dass sich der "Inhalt" der Variablen, auf den der Zeiger zeigt, verändert haben könnte. Davon aber geht der Compiler erstmal nicht aus, es sei denn es steht ausdrücklich so im Programmtext. Der Zeiger mag konstant bleiben, aber wichtig ist der Inhalt der variablen auf die der Zeiger zeigt. Der Compiler aber mag schon früher den Inhalt geladen haben und, weil er von nichts gegenteiligem weiss, bei der nächsten Verwendung des Inhalts den Zeiger garnichtmehr benutzen um den Inhalt erneut zu laden. Insofern gibt es zwischen Variablen und Zeigern auf diese Variablen keinen Unterschied. Ich hoffe das hilft weiter. Allerdings gibt es dieses Thema auch schon zu Tausenden Malen im Internet. Vielleicht suchst Du mal ein wenig.
Theor schrieb: > atomar - Eine Variable ist so groß (oder im Speicher oder einem Register > so gestaltet), dass sie nicht als ganzes mit einer Maschinenoperation > geholt, manipuliert oder gespeichert werden kann. Operationen sind oder sind nicht atomar, nicht Daten. Bei: volatile int i = 0; i += 1; ist die 2. Zeile bei x86 eine atomare Operation: inc mem bei ARM nicht: ldr r0,mem add r0,r0,#1 str r0,mem
:
Bearbeitet durch User
Für PRÄGNANT war das aber eine Menge Text. Mehr als alle vorherigen Beiträge zusammen.
Beitrag #5238925 wurde von einem Moderator gelöscht.
PS: Wenn mehrere Threads ins Spiel kommen, kann das, was bisher atomar war, nun nicht mehr atomar sein (oben, x86).
"volatile" ist ausschliesslich für Variablen da, welche sich durch etwas ändern können, was nichts mit dem Programm zutun hat.
Daniel A. schrieb: > "volatile" ist ausschliesslich für Variablen da, welche sich durch etwas > ändern können, was nichts mit dem Programm zutun hat. Für Anfänger (und einige Fortgeschrittene) ist nicht offensichtlich, dass ein im Programm mitten drin aufgeführter Exception-Handler nichts mit den Programm zu tun haben soll.
Ich verstehe es immer noch nicht. Bei einem Byte hat es keinen Einfluss, ok. Bei 2 Byte lade ich das erste bearbeite es und der 2. kann sich dann schon geändert haben. auch ok. und was soll da volatile daran ändern, dass man auf das 2. Byte zugreift, während ich noch beim 1. bin?? Spielt da der Compiler Türsteher und sagt: hier kommst du ned rein oder was? Sorry, aber irgendwie ist das nicht logisch..
Theor schrieb: > In beiden Fällen, kann und muss dem Compiler mit "volatile" gesagt > werden: "Verlass Dich nicht darauf, dass der Variableninhalt bei der > Ausführung des Programms noch derselbe ist, wie beim letzen Mal, als > diese Stelle im Code ausgeführt wurde. Also: Falls Du (Compiler) an > diese Stelle kommst, lade den Variableninhalt (den Inhalt des > Peripherieregister oder ähnliches) noch einmal in ein Register und > verwende nicht den alten Registerinhalt." > Ok, sagt mir immer noch nichts. Ich würde eher noch den alten nehmen, denn der ist noch der richtige. Beim neuen nämlich wurde das 2. Byte verändert. Da bringt es mir dann auch herzlich wenig, wenn mir der Compiler den falschen Wert nochmals ins Register ladet...
Beitrag #5238975 wurde von einem Moderator gelöscht.
Das sind ja auch verschiedene Dinge. Volatile: damit sagt man dem Compiler, dass diese Variable außerhalb seines Sichtbereichs eine Veränderung erfahren kann. Atomar: hier müssen Variablen, die in einem Interrupt modifiziert werden und im Programmablauf verwendet werden, davor geschützt werden, dass ein Interrupt sie verändert, während sie außerhalb gerade verarbeitet werden. Im Prinzip weden während der Verarbeitungszeit die Interrupts temporär ausgesetzt.
Du sprichst von Atomic! Atomare Zugriffe sorgen dafür, dass dir da kein Interrupt zwischen dengelt, und dir die Daten unter dem Arsch weg ändert, ohne das du oder der Kompiler es merkt.
_sepp_ schrieb: > Ich verstehe es immer noch nicht. Und ich verstehe diesen deinen Text leider nicht. Die Anzahl Bytes einer Variablen hat nichts mit "volatile" zu tun. Sie kann jedoch Einfluss darauf haben, ob eine Operation "atomar" ist. Was wiederum nichts mit "volatile" zu tun hat. Du hast https://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung und https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich gelesen?
Das scheint auch so ein Vortragsspezialist zu sein, aber ich habe mir da trotzdem mal angeschaut. Aber warum seine Leds einmal blinken (ohne Optimierung). Und einmal mit der Optimierung dann auf einmal nicht mehr, blicke ich nicht.. https://www.youtube.com/watch?v=ImHW6I0BoEs
_sepp_ schrieb: > Aber warum seine Leds einmal blinken (ohne Optimierung). > Und einmal mit der Optimierung dann auf einmal nicht mehr, blicke ich > nicht.. Er hat es doch schön erklärt: der Compiler will bei der Optimierung das Programm verkleiner und stell bei seinen Untersuchungen fest, dass in 'main' ja gar niemand da ist, der VAR verändert. Also: weg damit! Und schon geht es nicht mehr. Mit Volatile sagt man ihm, dass außerhalb seines begrenzten Horizonts mit VAR doch was passiert und er sie gefälligst nicht wegoptimieren soll. Und schon geht's wieder.
HildeK schrieb: > sepp schrieb: >> Aber warum seine Leds einmal blinken (ohne Optimierung). >> Und einmal mit der Optimierung dann auf einmal nicht mehr, blicke ich >> nicht.. > > Er hat es doch schön erklärt: der Compiler will bei der Optimierung das > Programm verkleiner und stell bei seinen Untersuchungen fest, dass in > 'main' ja gar niemand da ist, der VAR verändert. Also: weg damit! Und > schon geht es nicht mehr. > Mit Volatile sagt man ihm, dass außerhalb seines begrenzten Horizonts > mit VAR doch was passiert und er sie gefälligst nicht wegoptimieren > soll. Und schon geht's wieder. Was heisst wegoptimieren? Ich definiere int a = 5; Dann kommt der Compiler und macht mir die Variable a= 5 weg, weil sonst niemand sonst darauf zugreift und er glaubt, dass nur er Herr über die Variable ist. a ist ja hier auch nicht volatile. Also optimiert er es weg, obwohl ich später in irgend einer Funktion vllt. mal a= a+5; rechne. Damit er mir meine Variable nicht wegoptimiert, muss ich ja alle meine Variablen volatile definieren. Das ist doch Blödsinn.
_sepp_ schrieb: > Das ist doch Blödsinn. Hast du die Tipps und Links gelesen? Im FAQ Artikel steht es in epischer Breite beschrieben.
_sepp_ schrieb: > Das ist doch Blödsinn. Vielleicht! Aber reproduzierbar ist es, oder zweifelst du das auch an? Ich würde sagen, entweder ist es Blödsinn, oder du verstehst es nicht. Eine dritte Möglichkeit fällt mir nicht ein.
Arduino F. schrieb: > Ich würde sagen, entweder ist es Blödsinn, oder du verstehst es nicht. > Eine dritte Möglichkeit fällt mir nicht ein. Drittens: Er ist ein Troll. Was am wahrscheinlichsten ist ...
Nein, in deinem Beispiel veränderst du ja 'A'. In seinem Beispiel steht vermitlich nur drin: PORTB = VAR; und das in einer Dauerschleife. Also setzt er PORTB = 0, weil der Init-Wert von VAR ja 0 ist und macht weiter nichts. Wenn du dir bei einem optimierten Compilat mal Werte im Simulator ausgeben lässt, kommt es bei einigen immer wieder vor, dass er diese gar nicht kennt - deren Verarbeitung wurde einfach anders gelöst. Das funktioniert einwandfrei, wenn der Compiler über alles Bescheid weiß, nicht aber, wenn im zwischendurch jemand anders den Wert verändert. Primitives Beispiel: a=3; b=5; c=a+b; d=c*10; Wenn 'c' nicht im weiteren Programmverlauf verwendet wird, taucht sie garantiert nirgends auf - trotz des 3. Statements. Es wird dann d=(a+b)*10 daraus gemacht.
HildeK schrieb: > Nein, in deinem Beispiel veränderst du ja 'A'. > In seinem Beispiel steht vermitlich nur drin: > PORTB = VAR; > und das in einer Dauerschleife. > Also setzt er PORTB = 0, weil der Init-Wert von VAR ja 0 ist und macht > weiter nichts. > Wenn du dir bei einem optimierten Compilat mal Werte im Simulator > ausgeben lässt, kommt es bei einigen immer wieder vor, dass er diese gar > nicht kennt - deren Verarbeitung wurde einfach anders gelöst. Das > funktioniert einwandfrei, wenn der Compiler über alles Bescheid weiß, > nicht aber, wenn im zwischendurch jemand anders den Wert verändert. > Dass VAR 0 ist, sehe ich nirgends, ist ja gar nicht initialisiert. Hat wohl ein garbage value. Ich hätte jetzt eher gemeint, er optimiert es weg, weil es in der Schleife ist und sonst nichts mit dem Wert passiert als immer nur den gleichen Wert zuzuweisen, muss ja nicht 0 sein, kann ja auch 1 sein..
_sepp_ schrieb: > a ist ja hier auch nicht volatile. Also optimiert er es weg, obwohl ich > später in irgend einer Funktion vllt. mal a= a+5; rechne. Warum auch nicht. Wenn sonst nichts mit dem Wert von a passiert, wird er ja nicht gebraucht.
_sepp_ schrieb: > Dass VAR 0 ist, sehe ich nirgends, ist ja gar nicht initialisiert VAR war als globale Variable definiert, die ist in C inital '0'. War wohl in dem Video auch so umgesetzt, denn die LEDs blieben ja aus. Aber das ist nur ein Nebenschauplatz. Sie hätte auch jeden andern Wert haben können. Der Compiler hat sie als Variable wegen 'global' gar nicht mal verschwinden lassen, sondern eben dem LED-PORT nur ein einziges mal den Initialwert zugewiesen - weil er in 'main' keine Veränderung erkennen konnte.
HildeK schrieb: > sepp schrieb: >> Dass VAR 0 ist, sehe ich nirgends, ist ja gar nicht initialisiert > > VAR war als globale Variable definiert, die ist in C inital '0'. War > wohl in dem Video auch so umgesetzt, denn die LEDs blieben ja aus. > Aber das ist nur ein Nebenschauplatz. > > Sie hätte auch jeden andern Wert haben können. Der Compiler hat sie als > Variable wegen 'global' gar nicht mal verschwinden lassen, sondern eben > dem LED-PORT nur ein einziges mal den Initialwert zugewiesen - weil er > in 'main' keine Veränderung erkennen konnte. jetzt habs ich glaub geschnallt :P
A. K. schrieb: > Operationen sind oder sind nicht atomar, nicht Daten. Bei: > volatile int i = 0; > i += 1; > ist die 2. Zeile bei x86 eine atomare Operation: > inc mem Nein, leider nicht. Es ist zwar nur eine Asm-Instruktion, aber auch diese eine Operation ist nicht notwendigerweise atomar. Nur bei völlig veralteten X86ern mit nur einem Kern und nur einer CPU ist sie tatsächlich atomar. Wobei ich mir nicht einmal da ganz sicher bin, es gibt ja schließlich auch noch DMA... Sprich: die Faustregel "was sich mit einer Asm-Anweisung ausdrücken läßt, ist atomar" gilt nur für sehr simple Architekturen. Bei modernen leistungsfähigen µC/µP fällt man damit ziemlich sicher auf die Schnauze.
c-hater schrieb: > Nein, leider nicht. Es ist zwar nur eine Asm-Instruktion, aber auch > diese eine Operation ist nicht notwendigerweise atomar. Nur bei völlig > veralteten X86ern mit nur einem Kern und nur einer CPU ist sie > tatsächlich atomar. Was ist kurz drauf auch schon erwähnte. Aber so lange wir es mit den hier im Forum üblichen µCs ohne Betriebsystem zu tun haben, ist das weniger relevant. Da geht es eigentlich immer um Interrupts auf einem einzelnen Prozessor. > Wobei ich mir nicht einmal da ganz sicher bin, es > gibt ja schließlich auch noch DMA... Ja. Aber R-M-W Befehle auf Speicher, der im gleichen Zeitraum von DMA genutzt wird, sind schon etwas exotisch und ganz sicher weit jenseits des Horizonts des aktuellen Fragestellers. Da kannst du dann auch gleich mit den unterschiedlichen memory consistency models von ARM und x86 und damit verknüpfter Speicherbereichsverwaltung kommen und wirst damit auch viele erfahrenen µC-User aus der Kurve werfen.
:
Bearbeitet durch User
I_ H. schrieb: > Wobei man sich darauf auch nicht 100%ig verlassen kann, Operationen auf > volatile sind auch net atomar Volatilität hat doch nichts mit atomar zu tun ... Für Atomarität gibt es mutexe.
_sepp_ schrieb: > Ich verstehe irgendwie immer noch nicht wieso man volatile benötigt. Angenommen du hättest eine ISR, die ein Flag setzt und deine Main-Loop macht sowas wie:
1 | while (!flag) { |
2 | // wait
|
3 | }
|
dann würde der Compiler nicht erkennen können, dass flag auch mal den Wert 1 annehmen kann, wenn die Variable nicht volatile ist und die Schleife einfach zur Endlos-Schleife optimieren. Aber in einer ISR könnte flag auf 1 gesetzt werden. Dann muss man flag volatile deklarieren.
Ihr solltet mal in die FAQs hier schaun, zum Thema gibts da was was sehr informativ ist: https://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich Das sagt eigentlich alles.
Es wurde schon alles gesagt, nur nicht von jedem ;-) https://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung https://www.mikrocontroller.net/articles/Interrupt#Volatile_Variablen
A. K. schrieb: > Es wurde zwar schon alles verlinkt, aber noch nicht von jedem. ;-) Hm, stimmt. Jetzt wo du es sagst :D
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.