Hallo Zusammen,
ich will zur comple-Zeit bestimmte Konstanten berechnen. Doch aus irgend
einem Grund, wenn ich den avr-gcc verwende, werden diese nicht so
gerechnet wie ich es erwarten wuerde.
Die Konstanten sind jedoch richtig wenn der 'normale' gcc (ubuntu
systemcompiler) verwendet wird.
Folgender Code sollte fuer jede test-Variable 31 ergeben (8000000/(256 *
1000)):
Ich habe auch den avr-gcc 4.9.2 ausprobiert. Ergebnis ist gleich.
Das Verhalten ist auch gleich egal ob 'mPrescaler' ein '#define' ist
oder eine 'static const' variable (im C++ Fall).
Warum wird myTestVariable3 korrekt gerechnet, waehrend die anderen zwei
falsch sind?
Es scheint, dass die Multiplikation im Nenner schief geht.
Mir ist auch nicht klar wie der compiler gerade auf '134' kommt...
Sitzt der Bug jetzt vor dem Rechner oder im avr-gcc?
Wenn vor dem Rechner, wo ist dann mein Denkfehler?
Vielen Dank fuer Eure Hilfe,
-Foka
Kernelhacker schrieb:> Integer promotion ist die Ursache dieses Verhaltens.
Nein. Integer promotion ist zwar ein hübsches Stichwort, stimmt aber
hier nicht. Integer promotion ist die automatische Erweiterung von
Parametern arithmetischer Operationen, die kleiner als int sind, auf
int.
Hier gibt's keine integer promotion, weil die Konstanten schon int sind.
Das ist ein ganz simpler Überlauf bei der Berechnung des
Klammerausdrucks.
256 * 1000 ist nun mal 256000 und das passt nicht in ein AVR 16-bit int.
Vermutlich hat der avr-gcc über Warnungen auch gemeldet, daß es da einen
int-Überlauf gibt, nur - wer liest schon Warnungen. Ist doch einfacher
einen Compiler-Fehler zu vermuten. ;-(
Der Compiler muß im Übrigen zur Compile-Time exakt so rechnen, wie es
die HW auch tun würde, inkl. Überlauf, sonst wäre das tatsächlich ein
Compiler-Fehler.
Carl D. schrieb:> Vermutlich hat der avr-gcc über Warnungen auch gemeldet, daß es da einen> int-Überlauf gibt, nur - wer liest schon Warnungen. Ist doch einfacher> einen Compiler-Fehler zu vermuten. ;-(>
Das stimmt so nicht.
Wenn Du den Code, den ich oben gepostet habe, mit dem avr-gcc
duchrkompiliertst wirst Du feststellen, dass der Compiler nicht warnt.
Ich gehoere zu der Sorte die immer das '-Wall -Wextra' mit auf die
command-line aufnehmen.
Aufgefallen ist es mir auch nur weil ich eine Art 'sanity check'
eigebaut habe:
Markus F. schrieb:> Kernelhacker schrieb:>> Integer promotion ist die Ursache dieses Verhaltens.>> Nein. Integer promotion ist zwar ein hübsches Stichwort, stimmt aber> hier nicht.
Doch. Integer-promotion ist der Grund warum es auf dem x86 nicht
überäuft.
Und die, vom compiler angemeckerten, Variablen sind auch falsch
berechnet.
So wuerde ich es vom avr-gcc erwarten.
Der Vorschlag von Max funktioniert hier ueberigens auch sehr gut.
Allerdings gilt es auch nicht mehr wenn ich den Code mit dem g++
uebersetze und wie folgt anpasse:
Der GCC gibt bei Unsigned-Operationen niemals eine Overflow-Warnung aus,
da Unsigned-Operationen nach C-Standard nicht überlaufen können, sondern
per modulo 2**n auf den gültigen Wertebereich reduziert werden.
Deswegen warnt der AVR-GCC zwar bei
Markus F. schrieb:> Kernelhacker schrieb:>> Integer promotion ist die Ursache dieses Verhaltens.>> Nein. Integer promotion ist zwar ein hübsches Stichwort, stimmt aber> hier nicht. Integer promotion ist die automatische Erweiterung von> Parametern arithmetischer Operationen, die kleiner als int sind, auf> int.
Doch natürlich handelt es sich bei der Ursache des unterschiedlichen
Verhaltens hier um Promotion.
Der Code ist:
(uint16_t)256 * 1000
Das funktioniert nicht, wenn es keine Promotion von uint16_t auf ein
32 Bit int gibt. Wie es eben auf dem AVR der Fall ist, weil int dort 16
Bit hat.
Das es ohne den Cast genau so wenig funktioniert, ist ja wieder eine
separate Sache.
Bernd K. schrieb:> Markus F. schrieb:>> Kernelhacker schrieb:>>> Integer promotion ist die Ursache dieses Verhaltens.>>>> Nein. Integer promotion ist zwar ein hübsches Stichwort, stimmt aber>> hier nicht.>> Doch. Integer-promotion ist der Grund warum es auf dem x86 nicht> überäuft.
Blödsinn. Der Grund, warum es auf dem x86 nicht überläuft ist die Größe
eines ints auf dieser Plattform.
Wie willst Du ein int auf ein int promoten?
Kernelhacker schrieb:> Markus F. schrieb:>> Wie willst Du ein int auf ein int promoten?>> Das ist nicht der Fall. Es ist eine uint16_t zu int Promotion auf x86.
Stimmt. Ich hab' den Cast nicht gesehen, sorry.