Zum Inhalt springen
L

Das Video kommt von YouTube: erst beim Abspielen verbindet sich die Seite mit YouTube (Google).

04D.1 Funktion und Variable in eigene Datei auslagern; Header-Datei

Jörn Loviscach27:51 7.401 Aufrufe veröffentlicht Auf YouTube

Das Wichtigste aus dem Video

Tipp auf eine Zeit – das Video springt genau dorthin.

Transkriptautomatisch erstellt · 167 Zeilen
Herunterladen
  1. so jetzt haben wir eben diese Funktion Würfel geschrieben schön ist wenn man Funktionen sauber zusammenfasst in einzelne Dateien nicht alle Funktionen
  2. in die Main Datei reinschmeißt die hier dass da nicht alle mögliche Krempel drin rumfliegt diese Funktion die soll in ihrer eigene Datei sozusagen sie bauen
  3. eine eigene Datei sowieso Punkt C und dazu Headerdatei um diese Funktion auszugliedern ich zeig noch mal wie man das im Prinzip machen würde fangen würde
  4. neue Datei hier File new file oder einfach hier mit dem leeren Blattpapier eine neue Datei die
  5. speichern save S in das Verzeichnis am besten wo auch sowieso die anderen Dateien vom Projekt drin stehen neben MC speichern ich nenne
  6. die jetzt mal ganz überraschend Würfel diese Datei die Datei soll nacher auch kompiliert werden also mausglick rechts
  7. hier add steht netterweise schon Würfel C das sind die Dateien die nachher kompiliert werden das sollte ich jetzt
  8. schon mal sagen kompiliert werden werden die c-dateien kompiliert werden nicht direkt die Header datateien die Headerdateien werden dann ja nachher mit
  9. include eingebunden so erfährt der Compiler von den Headerdateien hier das sind die c-dateien erstmal was der Compiler wissen muss über die c-dateien
  10. erfährt er von den Headerdateien wir brauchen eine cdatei da steht drinnen wie die wfunktion funktioniert von innen und wir brauchen eine Headerdatei mit
  11. den Deklarationen ich speicher das also als würfelpunkt H und sie schreiben jetzt mal was sinnvolles in diese cdatei und diese Header Datei
  12. includeegs und solche Geschichten in die cdatei in die cdatei kommt diese Kiste rein glaube jetzt muss
  13. ich tatsächlich mal die Aufgabe rauslöschen so das kommt in die cdatei wie sieht meine Funktion von innen aus die
  14. cdateien sind Zusagen sozusagen die echten Programme die werden ja auch kompiliert die stehen hier in der Liste für den
  15. Compiler damit haben wir erstmal die cdatei in der Header datatei steht wie diese Funktion von außen aussieht was muss der
  16. Wissen um diese Funktion benutzen zu können eine Deklaration das ist die Deklaration keine schweifklammern mit dem programmtex sozusagen dahinter mit
  17. dem Text der Funktion dahinter sondern ein Semikolon hinten dran zu sagen okay das ist der Name meiner Funktion sie nimmt nichts und gibt eine ganze Zahl
  18. das braucht man nachher um die andere Datei zu kompilieren diese Datei hier die Headerdatei wird inkludiert
  19. in meiner mainatei wie hier das include Matth genauso kann ich jetzt sagen include jetzt Anführungszeichen weil das mein eigenes meinem eigenen Verzeichnis
  20. steht Würfel h die headdatei wird inkludiert jetzt kann ich mir den hier ne wo ist er denn den wür schon rausgenommen schon
  21. und jetzt MS so funktionieren in Würfel h findet deriler die ktion von außen aussieht der Compiler fängt an die
  22. mainatei zu übersetzen mainatei die übersetzt der findet den würfelh wie die würbelfunktion von außen aussieht die Deklaration und kann sie hier
  23. verwenden der Linker bindet dann nachher alles zusammen was der Compiler kompiliert hat der Linke muss dann irgendwo aber auch wissen wie d die
  24. würfelfunktion wirklich geht und dann stellt er fest in dieser Datei die der Compiler auch übersetzt hat in dieser Datei findet er die würfelf tion und
  25. bindet die beiden zusammen jetzt müsste das theoretisch funktionieren jetzt soll ich das den kompilationsprozess gleich noch mal aufmalen aber kann mal gucken
  26. ob es wirklich tut soweit so gut ich gehe mal bis hinten durch das Ergebnis kommt mir fürchterlich bekannt vor wie
  27. eben das sind jetzt noch keine include Guards drin sicherheitalber oder hier Singular der include GU fehlt
  28. mir hier in dieser Datei noch muss ich gleich noch machen aber sicher aber noch mal zum kompilationsprozess was macht jetzt dieses System im
  29. Hintergrund wir haben eine Datei die heißt main.c wir haben eine Datei die heißt
  30. wfelc und wir haben eine Datei die heißt Würfel H der Compiler nimmt die main. C
  31. Datei und macht daraus Objektcode ich schreib nur o wie es auch immer gerade auf dem System heißt
  32. dasselbe mit der würfelcdatei der Compiler nimmt die würfelcdatei und macht daraus objektcod diese Datei wird als solche übersetzt halbw in
  33. Maschinensprache noch nicht ganz in Maschinensprache in der mainatei kommt jetzt aber unsere Funktion Würfel
  34. vor damit der Compiler diese Funktion kompilieren kann muss er wissen was sie denn tut nimmt die delzahlen hat die fünf Argumente hat sie sieben Argumente
  35. gibt sie bullch zahlen er muss nicht wissen wie diese Funktion wirklich funktioniert von innen aber muss wissen wie diese Funktion verwendet wird dazu
  36. brauchen wir die Header datatei das habe ich jetzt strategisch gut gemalt also hier die Header datatei die brauchen wir da die wird per include reingeholt die
  37. Headerdatei damit der Compiler die Deklarationen hat damit er weiß wie denn die würfelfunktion im Prinzip läuft damit das übersetzen kann hier in
  38. dem Objektcode steht ein Platzhalter weiterhin drin für die würfelfunktion die ich da jetzt gerade hingeschmiert habe im Objektcode steht weiterin
  39. Platzhalter aber der Compiler kann es kompilieren weil er weiß wie die würfelfunktion im Prinzip läuft das sind Header
  40. Datei der nächste compilerlauf ist die Würfel C Datei das sollte ich vielleicht auch noch mal an der Embedded Workbench zeigen Main C wird kompiliert und Würfel
  41. C wird kompiliert die c-dateien werden kompiliert die würfelcdatei wird kompiliert daraus wird Objektcode der Compiler läuft zweimal und dann kommt
  42. der Linker der kommt einmal und hier läuft jetzt zweimal für jede cdatei läuft der Compiler einmal und danach kommt der
  43. Linker der bindet das zusammen zu einer ausführbaren Datei unter Windows wäre das Exi hier ist es keine Exi sonder was fürchterliches egalter Windows wäre das
  44. ein Exel Datei so eine ausfühbare Datei das macht der Linker der Linker sieht hier den
  45. Querverweis oh ich brauch die würelfunktion und in der anderen übersetzten Datei sieht er die würfelfunktion und schafft die
  46. Verbindung linker verbinden to link das Zusammenbringen diese Arbeitsteilung ist eine Maßnahme um Zeit beim Kompilieren zu sparen stellen sich vor Sie haben
  47. wirklich ein Betriebssystem oder was mit 10tausenden an Dateien dann wollen sie nicht jedes Mal alle 10.000 Dateien übersetzen sondern nur die eine die sich
  48. geändert hat 999 bleiben so wie sie waren und zum Schluss bindet man dieses neue Ergebnis dann mit den anderen Sachen wieder
  49. zusammen das wird auf dies Weise schneller effizienter durch diese arbeitszahung mit dem Compiler und dem
  50. Linker und hier das ist jetzt eben der Ärger der Compiler hier an dieser Stelle muss wissen wie die würfelfunktion denn zu verwenden ist dafür die Header
  51. Datei dafür bin ich hier dafür dieses hier eine Deklaration jetzt weiß der Compiler wie es geht na ja wie die Funktion verwendet er
  52. weiß nicht wie die Funktion gemacht ist aber das ist ja auch egal das haben wir hier stehen die wird getrennt kompiliert der Compiler weiß wie die Funktion
  53. verwendet dafür hier Würfel h ich könnte überhaupt mal das auskommentieren das Würfel h was dann passiert project
  54. make dann sagt er uns dann sagt er uns function Würfel deced implicitly der C standandard erlaubt das
  55. noch ich verwende eine Funktion Würfel die der Compiler nicht kennt im c-standard ist tatsächlich dann vorgesehen dass der Compiler sich
  56. einfach selbst was erfindet dann wie diese Funktion zu verwenden wird zu verwenden sei die klärt implicitly das natürlich total heikel
  57. und das ist im allgemeinen ja auch Unsinn was ich der Compiler dann da selber ausdenkt in anderen Sprachen ist es schtiicht greifend verboten da darf
  58. nicht gerade irgendwas erfunden werden das passiert wenn der Compiler nicht weiß was da angesagt ist dafür den
  59. hier jetzt könnte ich noch ein typischen Fehler zeigen ich ma den H gerade mal wieder gut
  60. so wenn Sie hier die falsche Funktion bauen wen Sie hier die Funktion Würfel XY Z bauen ihr Hauptprogramm verwendet die Funktion Würfel ihre Headerdatei
  61. sagt auch was vom Würfel aber wird gar keine Funktion Würfel geliefert sondern Funktion Würfel XY
  62. Z jetzt gibt's wirklich ein Fehler undefined external Würfel hier behaupte ich es gäbe eine Funktion Würfel das ist ja hin der
  63. mainateil in der mainateil wird Würfel h inkludiert an dieser Stelle behaupte ich es gäbe eine Funktion Würfel irgendwo verwende sie
  64. auch und der Linker sie sehen hier error while running linker der Linker stellt dann fest beim zusammenbinden da hat mich jemand betuppt es gibt keine
  65. Funktion namens Würfel es gibt vielleicht eine XY Z aber das weiß der Linker nicht dass es die eigentlich sein sollte der der Linker sieht keine
  66. Funktion namens Würfel macht deshalb hier Ärger genau was hier steht für Würfel die Implementierung wie die Funktion
  67. funktioniert die habe ich natürlich jetzt aus Main C rausgeschmissen das wäre auch noch eine spannende Geschichte was passiert wenn ich hier in der
  68. mainatei die auch noch mal drinen habe project make aha entry Würfel in Module Main blablabla
  69. redefined in Module Würfel eine erneute Definition und das hat natürlich wieder der Linker gemerkt der Linker sieht in der einen Datei mach das noch mal auf
  70. hier meine seh händische Skizze der Linker sieht in dieser Datei gibt's eine Funktion namens Würfel implementiert in dieser Datei gibt Funktion namens Würfel
  71. implementiert und dann sagt der Linker so nicht ich kann nicht zwei Sachen mit demselben Namen haben an der Stelle zumindest nicht sonst viicht schon aber
  72. an der Stelle nicht das ist dieser Fehler hier das ist wirklich ein Fehler so also hier aus der mainatei nehme ich die Funktion noch mal raus mit
  73. den Namen das muss ich vielle gerade noch mal sagen ich habe jetzt diese cdatei Würfel genannt und die H Datei Würfel genannt weil es für mich
  74. vielleicht da verständlich ist dass die Funktion Würfel heißt heißt nicht dass die Dateien auch Würfel heißen müssen vielleicht sollte ich noch mal hier klar
  75. machen ich schreib hier Würfel werfen was müsste ich jetzt alles umbenennen genau an zwei weiteren Stellen Datei heißt jetzt weiter
  76. würfelpt C hier in der Header Datei brauche ich dann den anderen Namen ich deklariere jetzt ja eine andere Funktion die Würfel werfen heißt und in der
  77. mainatei der Name der Datei ist derselbe aber da wo ich da wo ich die Funktion habe ich alle jetzt da noch einer da wo ich die Funktion anwende da brauche ich
  78. jetzt den anderen Namen mal gerade gucken project make wo ich dabei bin sie sehen noch mal die drei Arten wie Funktionen in C
  79. vorkommen das erste ist dass so eine Funktion eine Implementierung haben muss eine Definition sagt man dann C so wird die Funktion gemacht das Rezept
  80. ausbuchstabiert die Definition dann gibt es eine Deklaration die steht typischerweise in
  81. der Headerdatei die Deklaration wie sieht die Funktion von außen aus nicht wie sie von innen funktioniert keine Implementierung sondern nur wie sie
  82. verwendet wird was geht rein was geht raus vom Typ her Deklaration und dann gibt's den Aufruf einer Funktion das hier ist der Aufruf einer Funktion sie
  83. wird wirklich ausgeführt jemand kocht die Suppe nach dem Rezept
  84. noch mal was zu Deklarationen das kam ja dieses Semester noch nicht so ganz ausführlich dran in den Videos kam es irgendwo dran aber das war vielleicht
  85. ein bisschen zu unterschwellig in der Headerdatei da steht so eine Deklaration der C Compiler will bevor er eine Funktion und
  86. andere Sachen verwendet mindestens eine Deklaration sehen ich zeige mal sowas int F von mir aus eine Funktion heißt F und sie kriegt eine ganzsalige
  87. Variable und gibt von mir aus 23 zweimal zweimal diese ganzzealige Variable zurück jetzt eine andere
  88. Funktion die die erste verwendet hier könnte z.B sowas stehen wie return 3 mal F von X eine Funktion g die Funktion f verwendet wenn die in dieser Reihenfolge
  89. stehen dann ist der cciler glücklich es se die Funktion f hätte schon gegeben Entschuldigung die gibt's
  90. hier unten schon dann heißt jetzt eben F1 da unten sorry kleiner Showstopper noch mal project make so also ich kann eine Funktion verwenden wenn sie vorher
  91. definiert ist wenn die Implementierung vorher steht dann ist der ccpiler glücklich dann weiß er wie die geht sie können aber auch die Reihenfolge
  92. ändern dass sie die Funktion erst verwenden und dann im Compiler mitteilen wie die Funktion denn zu machen ist aber dann zeig jetzt einmal so was jetzt
  93. passiert jetzt gibt nämlich erstmger pro make jetzt haben wir wieder Dec implicit die Funktion f hat er hier oben nicht gehabt und hat sich was erfunden nicht
  94. gut aber wir können den Ärger verhindern mit einer Deklaration so sie deklarieren die Funktion f wie versprechen es gibt hier irgendwo
  95. eine Funktion f die nimmt eine ganze Zahl und liefert eine ganze Zahl jetzt ist der Compiler glücklich wenn er die Funktion g bauen will soll hier kan er
  96. den kann er die Funktion f dann einsetzen und hier unten erfährt er wie die Funktion f wirklich funktioniert ich ma mal
  97. make so geht das also wenn Sie eine Deklaration haben dann kann der Compiler auch die Funktion verwenden und das haben im Endeffekt mit der Header Datei
  98. in der Headerdatei steht die Deklaration drin und deshalb kann der Compiler die Funktion verwenden das ist hier eine sag mal ihr weniger typische Art Deklaration
  99. zu verwenden dass wir eine Funktion erst deklarieren und später definieren in derselben Datei normalerweise wird man die Deklaration in die head datatei
  100. schreiben und die Definition in die cdatei schreiben ich sollte noch der formher vielleicht vorschreiben das ist die
  101. Deklaration das hier unten ist die Definition und dieses hier ist der Aufruf einer
  102. Funktion drei Arten wie Funktionen vorkommen soll ich etwas klarer machen F von X das ist der Aufruf nicht dreal F von X F von X ist der Aufruf der
  103. Funktion ihr könnte auch übrigens damit da keine Bedenken gibt 4 + X drin F V 4 + X wäre dann der
  104. Aufruf jetzt noch der include Guard diese Headerdatei die sieht so aus wie man sie normalerweise nicht schreiben würde hier wä es kein Problem später ist
  105. es ein Problem des machen wir das sofort richtig ich zeige das noch mal hier in der Skizze es könnte sein dass ein eine cdatei was heißt es könnte sein später
  106. im Leben ist es dann so dass in einer cdatei ganz viel Headerdateien inkludiert
  107. sind und dann gibt's den Ärger es ist auch möglich in Headerdateien Header datateien zu inkludieren und auch sinnvoll denken Sie
  108. an messpt H brauchen sie irgendwo den Sinus oder Standard buol sie brauchen irgendwo in der Header datatei fals und true dann brauchen Sie Standard buol
  109. stell sowas vor wie Standard buol Standard BU könnte als solches wieder in Headerdateien inkludiert sein dann hab wir zum Schluss den Ärger es kann
  110. passieren dass beim Kompilieren dieselbe h datatei mehrfach vorkommt weil sie in der einen h datatei vorkommt und in der anderen head Datei vorkommt noch mal mit
  111. includes das hört sich esoterisch an aber wenn sie wirklich ein vernünftig großes System haben D mit 20 30 Dateien wird es regelmäßig passieren dass sie
  112. includes in includes haben und head Dateien im Endeffekt mehrfach vorkommen damit das keinen Ärger gibt zweimal Datei in den Compiler nicht so
  113. gut damit das keinen Ärger gibt dafür gibt's den include Guard und zwar so jetzt kommt der Präprozessor und das
  114. ist eigentlich das einzige was man heute noch mit Präprozessor machen sollte es seit den man hat Antike Software also eine Anweisung an den prprozessor if Def
  115. wenn nicht definiert und zwar ein Symbol dies Symbol wird man sich typischerweise aus dem Dateinamen damit es eeutig ist Würfel unr h wird man das gerne nennen
  116. wenn dieses Symbol nicht definiert ist dann nehme alles was dahinter steht was ich jetzt mache ist okay wenn das nicht definiert ist dann sage ich
  117. dann definiere ich das Symbol define [Musik] def ist sozusagen schweifklommer
  118. zuif das ist der include Guard das sieht wenn man zum ersten Mal so sieht sieht es haarsträubend aus wenn sie sich solche Dateien wie mess.h oder
  119. standardlip. angucken stellen Sie fest oh das kann man auch noch weiter treiben aber das ist Derg in Standardform in Reinform wenn der prprozessor also das
  120. was vor dem Compiler läuft wenn der prprozessor diese Datei zum ersten Mal sieht weiß er nichts von einem Symbol namens würfel_terrich h na schön denkt
  121. er sich mach wir weiter if not defined es ist nicht definiert also macht er weiter es ist nicht definiert dann definiert er das Symbol als nicht sie
  122. könnten hier auch irgendwas hinterschreiben dann wird er das Symbol als GK was auch immer definieren er definiert das Symbol als nichts aber das
  123. Symbol ist jetzt definiert er liest die Deklaration sozusagen schweifklammer zu Ende wenn jetzt bei demelben
  124. kompilationslauf für dieselbe c-datei diese Datei noch mal vorkommt sieht der Präprozessor oh ich habe schon ein symbolnamens Würfel h es ist definiert
  125. und er überspringt bis dahin und und damit ist der Teil hier in der Mitte hier nur einmal gelesen wollen beim zweiten Mal gibt es dieses
  126. Symbol und das ganze was in dem iF drin wird übersprungen das ist der Trick bei den include GUID das ist eine historische Kiste die irgendwie nicht
  127. wegzukriegen ist einige Compiler Hersteller haben etwas das nennt sich pragma W stattdessen aber das ist
  128. offiziell nicht standardisiert das wird auf jeden Fall funktionieren letzte Geschichte mit dem zufallsding damit sie einmal noch mal
  129. die cdatei und die Header datatei anfassen geh noch mal in die cdatei hier gibt's ja meine interne Zahl a die jedes
  130. mal irgendwie weitergestellt wird und ich möchte gerne dass man diese Zahl aber auch einstellen kann dass man
  131. insbesondere zu Beginn des Programms z.B a mit Hilfe der Uhrzeit oder irgendeiner Messung oder was auch immer einstellen kann dass es sich zufälliger anfühlt
  132. schreiben Sie eine Funktion mit deren H für Sie diese Zahl a einstellen können wird natürlich noch so ein paar andere Änderungen nach sich
  133. ziehen diese Funktion die fängt ja immer an in dem A = 42 ist zu Beginn des Programms ich kriege immer dieselbe FG an Zufallszahlen ab Programmstart ich
  134. möchte gerne zu Programmstart oder auch zu anderen Zeitpunkten eine andere Zahl einstellen können für a damit ich nicht immer wieder dieselbe Folge Kriege oder
  135. sogar auch um dieselbe Folge tatsächlichoduzi zu könen wenn zum Schluss wieder auf 42 stellen dann fängt da ja wieder
  136. an diese Variable a die darf jetzt nicht mehr einfach innerhalb dieser schweifklammern stehen diese Variable a muss auch in einer anderen Funktion
  137. zugänglich sein wir nehmen die da raus das war mein Gedanke den habe ich etwas kriptisch formuliert so haben sie eine statische variable innerhalb der
  138. Datei diese Variable ist jetzt in der Datei Würfel C sichtbar und sonst nicht eine statische variable wenn Sie das hier weglassen können Sie die Variable
  139. auch sogar aus anderen Dateien sehen wollen sie aber typischerweise nicht lieber verbergen eine statische variable innerhalb der
  140. Datei und jetzt brauche ich noch eine Funktion mit der ich diese Variable setzen kann eine Funktion die also nichts
  141. zurückliefert seed würde man die ja normalerweise nennen sehen
  142. heißt auch in C s Rand se random dieser Funktion gebe ich ebenso ein Bit ohne
  143. Vorzeichen B Beit ist und schmeiße dieses B in a rein das war was mir vorgeschwebt hat größer
  144. hier so in der Datei C gibt es jetzt also versteckt in der Datei sollte ich sagen gibt es eine Variable namens a zwei Funktionen greifen auf diese
  145. Variable zu seed und Würfel werfen zu programmbegn wird die Variable auf 42 gesetzt mit seed können Sie diese
  146. Variable auf ein anderen Wert setzen den sie wollen und mit Würfel werfen na ja passiert dasselbe was vorher passiert ist dieses a greift in
  147. beiden Fällen auf diese Variable zu und dieses a hier ist nicht haben wir hier auch noch ein a genau das ist ein anderes a dieses a hier ist eine lokale
  148. Variable in der Funktion Main das ist für den Compiler als ob der hier Karl Egon heißen würde und als ob dieses hier ernst augus heißen würde dieses a die
  149. heißen für uns als Menschen gleich die beiden Variablen aber für den Compiler sind das zwei paar Schuhe das ist immer ein bisschen schwierig am
  150. Anfang ich zeige gerade noch mal was hier wirklich passiert statics so geh auf in der Datei Würfel gibt es
  151. die statische variable static namens a und die steht schon auf irgendeinem Wert 2 x 16 + 10 42 Überraschung also diese Variable a steht schon auf irgendeinem
  152. Wert in dieser Datei Würfel C ist die versteckt jetzt fange ich hier an zu arbeiten in meiner
  153. mainfunktion guck mal bei Locals da gibt's auch eine Variable a das ist diese hier die heißt zufällig so diese lokale Variable wie diese statische
  154. Variable in der anderen Datei aber das stört den Compiler nicht das sind zwei verschiedene Sachen ich zeig so ausführlich weil das oft missverstanden
  155. wird wenn zwei Variablen gleich heißen heißt das nicht das ist die gleichen Sinn es hängt von den Umständen ab wie die verwendet werden wo sie definiert
  156. werden korrekter Einwand ich müsste die Funktion natürlich auch
  157. verwenden seed wird ja noch gar nicht verwendet haben sie aufgepasst was müsste ich jetzt überhaupt tun damit ich diese Funktion seed verwenden
  158. kann also die müsste deklariert werden Würfel werfen hatten wir deklariert in der Headerdatei seed müssten wir auch deklarieren also den hier einmal
  159. kopieren c h so jetzt habe ich dann auch eine Deklaration diese Deklaration in der
  160. Header Datei wird in der mainatei eingelesen an dieser Stelle erfährt unsere mainatei erfährt der Compiler beim Verarbeiten
  161. der mainei so an dieser an dieser Stelle erfährt der Compiler beim Verarbeiten der mainei dass es so eine Funktion seed
  162. gibt die einen bit ohne Vorzeichen nimmt und nichts lief an der Stelle und deshalb kann ich sie jetzt verwenden hier z.B sagen
  163. seed 42 wird natürlich genau das machen was wir vorher hatten also 43 hier müsste jetzt irgendwas stehen wie hole die aktuelle Uhrzeit nicht die
  164. Zahl 43 sondern die hle hole die aktuelle Uhrzeit oder wenn Sie sagen wollen ich hätte gerne noch mal die selbe Folge an
  165. Zufallszahlen auf diese Weise geht's dann hier wieder los mit derselben Vorg Zufallszahlen weil sie denselben Wert a noch mal haben so würde das Ding dann
  166. verwendet werden jetzt müssten wir sogar andere Ergebnisse haben für die Statistik mal gucken was der dazu
  167. sagt Locals oh ja Mittelwert ist jetzt 3,45 sind auch tatsächlich andere Zahlen die rauskommen

Zum Nachlesen