Guten Tag. Ich glaub jetzt brauch ich eure Hilfe. Ich hab eine "komplizierte" Rechnung in Einzelschritte aufgeteilt, weil sie nicht funktioniert hatte. [ich programmier mit AVR-Studio 6 und Atmega8] Hier die ursprüngliche Zeile (tc ist uint32_t): tc = 65536-(256*TimerCountOVF+TCNT0)/24; Als erstes hab ich die Variablen durch Zahlen ersetzt die ich kenne: tc = 65536-(256*1953+32)/24; Weil das immer noch nicht funktioniert hat (ich lese das Ergebnis aus und es steht falsch drin) hab ich folgendes probiert: Ich hab die Rechnung in einzelschritte aufgeteilt und immer das Teilergebnis vorausgesetzt. tc = 65536-20833; //funktioniert usw... dann komm ich zu diesen Schritten tc = 1953*256; tc = tc+32; tc = tc/24; tc = 65536-tc; Das funktioniert NICHT. Jetzt hätte ich gedacht, es liegt doch an einem Überlauf oder so - aber DAS funktioniert: tc = 499968; tc = tc+32; tc = tc/24; tc = 65536-tc; Also schließe ich darauf, dass das mit dem * nicht klappt. Aber was??? Vielen Dank schonmal für eure Hilfe, Beste Grüße, Elf
Probier mal an Stelle von
> tc = 1953*256;
das hier
tc = 1953L * 256L;
aus.
Und überleg dann, was geschieht.
Tip: Wie groß kann ein int werden? Und welchen Datentyp haben
numerische Konstanten?
> (256*1953+32) Wird in int gerechnet, und läuft über. > 1953*256 Dito. Elf schrieb: > Hier die ursprüngliche Zeile (tc ist uint32_t): > > tc = 65536-(256*TimerCountOVF+TCNT0)/24; Dass tc ein uint32_t ist, ist ziemlich irrelevant. Der Typ auf der linken Seite beeinflusst nämlich nicht, was auf der rechten Seite passiert.
In einer Zuweisung hat der Datentyp links keinen Einfluss auf die Rechnung rechts.
Dann kann ja auch gleich der passende Wettbewerbsartikel verlinkt werden: http://www.mikrocontroller.net/articles/Plattformunabh%C3%A4ngige_Programmierung_in_C#Integer-Berechnungen
Rufus Τ. Firefly schrieb: > Und überleg dann, was geschieht. Mhhh... vielleicht rechnet er dann in Long? Okay, ich wusste nicht, dass der C-Compiler überlaufen kann. Aber jetzt weiß ich's :) Stimmt denn meine Annahme? Werde es gleich probieren... Vielen Dank euch allen.
Der Compiler kann nicht überlaufen, aber dein Rechenergebnis. tc = 1953*256 Int * Int = Int, nur das Ergebnis 499968 ist für Int zu groß - läuft also folglich über.
unglaublich. Das war tatsächlich der ganze Fehler und jetzt läuft's einwandfrei. Ihr seid die Besten xoxo
ist es dann so, dass BPM = (60000000/(65536-cnt_pres))/24; nur deshalb funktioniert, weil 600... automatisch schon ne Long ist und deshalb die ganze Rechenoperation in Long ausgeführt wird? Gruß, Elf
Elf schrieb: > nur deshalb funktioniert, weil 600... automatisch schon ne Long ist und > deshalb die ganze Rechenoperation in Long ausgeführt wird? Ja. Willst Du Dir jetzt jeden Sachverhalt einzeln abgesegnen lassen?
J.-u. G. schrieb: > Ja. Willst Du Dir jetzt jeden Sachverhalt einzeln abgesegnen lassen? Brauchst du ne Antwort auf die Frage? Falls ja: Nein Wenn nicht: Ein "Ja" hätte auch gereicht. Trotzdem Danke. PS: War das jetzt so genervt gemeint, wie ich es verstanden habe oder bin ich nur zu sensibel für dieses Forum? Gruß, Elf
Elf schrieb: > PS: War das jetzt so genervt gemeint, wie ich es verstanden habe oder > bin ich nur zu sensibel für dieses Forum? Es war wahrscheinlich so gernervt gemeint wie du es verstanden hast aber das ist hier im Forum normal. Manch einer ist hier recht sensibel und reagiert dann so. Deine Frage finde ich OK, denn das wird nur in wenigen Lehrbüchern wirklich erklärt. Diesen Stolperstein in C hab ich auch mitgenommen bei meinen ersten µC-Programier-Experimenten und stand erstmal mit fragendem Gesichtsausdruck übern Quellcode.
Michael Köhler schrieb: > Deine Frage finde ich OK, Vielen Dank für die aufmunternden Worte. Ich habe viel gelernt hier :) Thema-Ende. Gruß, Elf
Michael Köhler schrieb: > Diesen Stolperstein in C hab ich auch mitgenommen bei > meinen ersten µC-Programier-Experimenten und stand erstmal mit fragendem > Gesichtsausdruck übern Quellcode. Ach, und in jeder anderen Hochsprache (neben C) oder gar in Assembler gibt es keine Datentypen und keinen Zahlenüberlauf?
Wegstaben Verbuchsler schrieb: > Ach, und in jeder anderen Hochsprache (neben C) oder gar in Assembler > gibt es keine Datentypen und keinen Zahlenüberlauf? In PL/I ist das Produkt aus FIXED(5,2) und FIXED(7,1) vom Typ FIXED(13,3). Ein Überlauf kann in der Multiplikation innerhalb der Grenzen der Implementierung also nicht auftreten. Siehe http://publibfp.boulder.ibm.com/cgi-bin/bookmgr/BOOKS/IBM3L101/3.3.1.2?SHELF=ibmsh306&DT=19950506201638#TBLFIG16 Im aus Unix stammenden "bc" (Basic Calculator) gibt es tatsächlich keine Datentypen und die Grenze zum Überlauf liegt (fast) nur in den Ressourcen des verwendeten Rechners.
A. K. schrieb: > In PL/I ist das Produkt blablablablablabla Dann programmier halt deinen Atmel in deiner tollen Sprache...
> Ach, und in jeder anderen Hochsprache (neben C) oder gar in Assembler > gibt es keine Datentypen und keinen Zahlenüberlauf? Wie weit oben hätten's denn gerne? Der Datentyp Variant (Visual Basic) rüstet z.B. automatisch auf, wenn was nicht passt. Scriptsprachen genauso. Andere Programmiersprachen werfen Exceptions. Je nachdem, aus welcher Richtung man kommt, ist so ein Überlaufverhalten gerade nicht offensichtlich. > PS: War das jetzt so genervt gemeint, wie ich es verstanden habe oder > bin ich nur zu sensibel für dieses Forum? Deine Frage war gut, denn sie zeigte, dass du verstanden hast.
Wegstaben Verbuchsler schrieb: > Ach, und in jeder anderen Hochsprache (neben C) oder gar in Assembler > gibt es keine Datentypen und keinen Zahlenüberlauf? Was hat das mit dem Problem zu tun? Der TE ist über den Stein gestolpert, dass der Datentyp links vom =-Zeichen nicht die Bereich rechts vom =-Zeichen bestimmt sondern lediglich durch die Größe der benutzten Konstanten bestimmt wird. Ich rede jetzt übrigens nur von Beispielen, die dem hier im Thread genannten entsprechen aber ich bin mir auch sicher, dass hier der ein und andere Volldepp rumrennt, der immer noch ein Lücke findet. Ein bischen mitdenken und überlegen, was der Gegenüber gemeint haben könnte ist hier im Forum leider allzuoft als Mangelware zu betrachten... :(
Michael Köhler schrieb: > er TE ist über den Stein > gestolpert, dass der Datentyp links vom =-Zeichen nicht die Bereich > rechts vom =-Zeichen bestimmt sondern lediglich durch die Größe der > benutzten Konstanten bestimmt wird. Genau, das ist weder C-spezifisch, sondern gibt es auch in anderen Hochsprachen, und insbesonder in Assembler ;-)
Wegstabenverbuchsler schrieb: > Genau, das ist weder C-spezifisch, sondern gibt es auch in anderen > Hochsprachen, und insbesonder in Assembler ;-) Blödsinn. Jeder mir bekannte Assembler berechnet Integers zur Entwurfszeit einfach mit dem größten ihm bekannten Integer-Datentyp und meckert, wenn man so ein Entwurfszeit-Ergebnis irgendeiner Laufzeit-Entität zuweisen möchte, die es nicht fassen kann. Das Verhalten von C, per Default zur Entwurfszeit nur mit 16Bit zu rechnen und bei Bereichsüberschreitung von numerischen Literalen noch nicht einmal zu warnen, war schon vor 40 Jahren idiotisch und ist es heute erst recht. Das fällt sogar noch hinter die Fähigkeiten der aus heutiger Sicht steinzeitlichen Assembler zurück, zu denen C ursprünglich mal als Erweiterung in Form eines simplen Satzes primitiver Macros geschrieben wurde. Die Syntax von C hat sich seitdem zwar gar fürchterlich aufgebläht, aber die Benutzbarkeit der Sprache ist dadurch kein bissel besser geworden. Ganz im Gegenteil... Das ist einfach unterirdisch. C halt. Eine Sprache für halbwissende Ignoranten. Vor 40 Jahren genauso wie heute. Na gut, haben wir also letztlich doch noch einen Vorteil von C gefunden: Die Kontinuität... Jeder halbwissender Ignorant in all den Jahrzehnten fühlte sich natürlich toll, wenn er dem Nachwuchs auf vielen Seiten erklären konnte, wo überall die vielen Tücken dieser unlogischen Scheiß-Sprache lauern. Auf die Idee, den ganzen merkwürdigen Quatsch einfach durch eine wirkliche SPRACHE zu ersetzen, ist eigenartigerweise nur eine Minderheit gekommen... Ich folgere daraus, daß C-Programmierung ein erhebliches Potential hat, das menschliche Gehirn komplett auszubrennen. Ja, ich merke das auch jedesmal, wenn ich selber gezwungen bin, in C zu programmieren. Das ist wirklich überaus anstrengend und fehlerträchtig und ich danke jedesmal Gott, wenn wieder ein Projekt kommt, wo nicht C explizit gefordert wird und ich selber eine bezüglich des Ziels sinnvolle Sprache wählen kann (wobei das Ergebnis durchaus variabel, aber niemals C ist).
@c-hater: ...und was wäre dann eine "sinnvolle" Programmiersprache? Ich bin nicht auf C festgenagelt, Deinen beiden Posts nach gibt es bessere und weniger fehlerträchtige Umgebungen. Ich denke, das ist eine Diskussion, die religionsartig vonstatten geht. Der eine schwört auf diese, der andere auf jene Sprache. Es gibt keinen Konsens, den alle akzeptieren. Servus Pe
c-hater schrieb: > Das fällt sogar noch hinter die Fähigkeiten der aus heutiger Sicht > steinzeitlichen Assembler zurück, zu denen C ursprünglich mal als > Erweiterung in Form eines simplen Satzes primitiver Macros geschrieben > wurde. Die Syntax von C hat sich seitdem zwar gar fürchterlich > aufgebläht, Eigentlich ... nicht. Syntaktisch hat sich in C seit den Zeiten eines K&R nicht wahnsinnig viel getan. Gerade das C-Gremium ist sehr konservativ, wenn es darum geht, Änderungen an der Sprache abzusegnen. > Das ist einfach unterirdisch. C halt. Eine Sprache für halbwissende > Ignoranten. Nicht wirklich. C ist halt keine Sprache für Leute, die eine Tante zum Lulu-gehen brauchen. Gerade deshalb ist es wichtig, sie von der Pieke auf zu lernen. Und wie sich die Datentypen in einer Berechnung bestimmen, sorry, aber das steht tatsächlich in so ziemlich jedem Lehrbuch, das sein Geld wert ist. Denn das ist ein wichtiger Punkt in der Expression Evaluation. > Ich folgere daraus, daß C-Programmierung ein erhebliches Potential > hat, das menschliche Gehirn komplett auszubrennen. Deine Folgerung ist falsch. Die Folgerung sie du ziehen solltest ist, dass man C nicht durch Zusammenfragen von anlassbezogenem Achtelwissen in Foren lernen kann, sondern sich von ordentlicher Literatur durch das Thema führen lassen sollte. Selbst dann bleiben noch Detailfragen offen, aber nicht mehr auf dem Level von "Wie bestimmen sich eigentlich die in Ausdrücken benutzten Datentypen und wie beeinflussen diese die Art und Weise, wie der Compiler die Operation in Code umsetzt". So wie du das weiter oben ja auch schon korrekterweise angedeutet hast. > Das Verhalten von C, per Default zur Entwurfszeit nur mit 16Bit > zu rechnen mit int, aber ... geschenkt > und bei Bereichsüberschreitung von numerischen Literalen noch > nicht einmal zu warnen Dein Compilerbauer kann Warnungen einbauen soviele er will. Der C-Standard schreibt lediglich vor, welche Fehler gemeldet werden müssen. Aber Warnungen kann jeder machen wie er will. >, war schon vor 40 Jahren idiotisch und ist es > heute erst recht. Ganz im Gegenteil. Es soll keinen Unterschied zwischen
1 | int j = 40000; |
2 | int k = 40000; |
3 | |
4 | long l = j * k; |
und
1 | long l = 40000 * 40000; |
geben. Denn beides sind dieselben Operationen. Ob da jetzt Variablen involviert sind (und die 40000 auf irgendwelchen anderen Wegen entstehen, die für den Compiler nicht einsichtig sind), darf keinen Unterschied im Ergebnis machen. Also muss der Compiler genau das tun, wenn er den Ausdruck durch das Constant Folding vereinfacht, was auch passieren würde, wenn der Ausdruck zur Laufzeit berechnet werden würde. Wenn er nett ist, dann wirft er eine Warnung (wozu er nicht verpflichtet ist). Aber als Ergebnis muss Bit für Bit dasselbe rauskommen (inklusive Overflow) - dazu ist er durch die 'As-If' Regel verpflichtet. Und in früheren Jahren war das gar nicht so einfach, weil der Compiler zb für Floating Point Berechnungen dann auch zb das Verhalten der FPU der Zielhardware nachbilden musste. Du magst C nicht. Das ist dein gutes Recht. Aber hör bitte auf mit deinem Halbwissen über C über die Sprache zu schimpfen. C ist sicher keine einfache Sprache und es gibt viele Details, die man wissen muss und ja, einige Details sind nicht so prickelnd gelöst. Aber all das kann man lernen und wenn man erst mal ein paar grundlegende Basisprinzipien verstanden hat, die wesentliche Grundlagen der Sprache bilden, dann versteht man bei manchen Dingen um einiges besser, warum die Dinge genau so sind wie sie sind. Viele empfinden C gerade im µC-Bereich als einen brauchbaren Mittelweg zwischen der Befreiung von den ebenfalls vielen kleinen Details, die man in der Assembler-Programmierung kennen und können und beherzigen muss und dem Overhead, dem man sich durch die Verwendung einer Hochsprache mit möglichst guter Fehlererkennung (auch zur Laufzeit) aufzwirbelt. Und in diesem Marktsegment macht C gar keine so schlechte Figur.
Karl Heinz Buchegger schrieb: > Ob da jetzt Variablen > involviert sind (und die 40000 auf irgendwelchen anderen Wegen > entstehen, die für den Compiler nicht einsichtig sind) Das ist doch Unsinn. Natürlich weiß der Compiler immer, ob eine Operation zur Entwurfszeit (eigentlich: Compilezeit) geschieht oder zur Laufzeit. Dementsprechend könnte er auch problemlos sinnvoll warnen, wenn eine Warnung nötig ist, nämlich genau dann, wenn irgendein Entwurfszeit-Resultat einer Laufzeit-Entität zugewiesen wird, die es nicht fassen kann. Jeder primitive Assembler beherrscht das und natürlich könnten moderne C-Compiler das problemlos ganz genauso leisten. > darf keinen > Unterschied im Ergebnis machen. Das ist doch nur ein C-Axiom, keine sachlich begündete Notwendigkeit oder gar etwas Wünschenswertes. Und es ist darüber hinaus ein sinnloses und fehlerträchtiges Axiom, welches dem Programmierer Arbeit aufbürdet, die die Maschine viel besser und zuverlässiger selber erledigen könnte. Allein die Existenz dieses gesamten Threads beweist das doch schon absolut zweifelsfrei, oder nicht? Der Auslöser war ja wohl offensichtlich der fünfundzwanzigmillionste Möchtegern-C-Programmierer, der sich damit in's Knie gefickt hat. Wenn man sich übrigens mal näher mit den Ursprüngen von C beschäftigt hat, dann weiß man auch, wie dieser Schmutz überhaupt in die Sprache gelangt ist. Denn de facto war die Unmöglichkeit, numerische Overflows des Präprozessors im zugrunde liegenden Assembler abzufragen (der damals auch zur Entwurfszeit nur mit 16 Bit signed gerechnet hat), der eigentliche Grund für dieses ziemlich sinnlose und fehlerträchtige Verhalten des C-Aufsatzes. Und nur, weil dies vor 40 Jahren mal ein Problem war, schleppt C den Scheiß bis heute mit. Das ist zwar völlig idiotisch, aber eben Kontinuität. Manche Leute versteigen sich sogar soweit, das als "Abwärtskompatibilität" zu bezeichnen und als etwas positives zu sehen. Nicht zuletzt die Hüter des C-Standards... Das einzige, was ich zur Entlastung von C anführen kann, ist: Es gibt etliche andere Sprachen, die ähnlich idiotische Altlasten mit sich herumschleppen...
c-hater schrieb: > Blödsinn. Tja, warum wohl ist heute nicht Ada und auch nicht Assembler die dominierende Sprache in der Controllerprogrammierung? Offenbar sind die Eigenwilligkeiten der Sprache C bei weitem nicht das Argument, das du uns hier gern weiß machen möchtest. Mit denen kann man sich arrangieren, wenn man das einmal gelernt hat, der Aufwand für das Lernen ist einmalig. Der exorbitante Aufwand, den man allein für die logische Fehlerfreiheit eines größeren Assemblerprogramms treiben muss (und zwar sowohl bei der Erstellung als auch bei der Pflege) schließt in fast allen praktisch relevanten Bereichen, in denen man mit der Software Geld verdienen muss, die Nutzung von Assembler als erste Wahl einfach mal aus. Das kann und will keiner bezahlen, vor allem nicht $KUNDE. ;-) Ada wäre sicher interessant, aber ernsthaft durchgesetzt hat es sich außerhalb einiger Nischen halt doch nicht.
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.