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.
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.
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:> 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.
> 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
intj=40000;
2
intk=40000;
3
4
longl=j*k;
und
1
longl=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.