zugehörige Warnung die auf die (erste) Stelle der Verwendung des defines
zeigt:
../timer-test.c:190: warning: overflow in implicit constant conversion
Was geht da schief?
Gruß,
Jans
Jan Mayer wrote:
> ../timer-test.c:190: warning: overflow in implicit constant conversion>> Was geht da schief?
^ macht etwas anderes als du denkst...
Was du suchst ist 1<<16 anstelle von 2^16.
@ Jan Mayer (Gast)
>// Zeiten für den uController berechnen (65536 = 2^16 = 16-Bit Timer, kein
Prescaler)
>#define START (unsigned short) ((unsigned long) F_CPU/(2^16) *
MY_TIME/1000)
Das ist ungünstig, weil der COmpiler die Rechnung von links nach recht
durchzieht und dadurch grössere Rundungsfehler entstehen. Prinzipiell
immer erst alle Multiplikationen machen und dann erst alle Divisionen.
Ausserdem, was soll der Quark mit den doppelten Casts? Und immer eine
Klammer um alles, sonst gibts mal böse Überaschungen. Das L bei der 2
ist wichtig, um dem Compiler zu sagen dass er mit Long rechnen soll.
Ohne Angabe rechnert er nämlich mit int, un das macht den Overflow.
#define START (F_CPU * MY_TIME/(2L<<16 * 1000))
@ Benedikt K. (benedikt)
>^ macht etwas anderes als du denkst...
Hehe, das ist eine XOR Verknüpfung. ;-)
>Was du suchst ist 1<<16 anstelle von 2^16.
Das macht bei int aber immer noch nen Overflow.
MFg
Falk
Falk Brunner wrote:
>>Was du suchst ist 1<<16 anstelle von 2^16.>> Das macht bei int aber immer noch nen Overflow.
Stimmt, es steht in einer Klammer, also wird es als int gerechnet, ehe
das Ergebnis auf logn gecastet wird (oder ist das falsch) ?
Hallo,
autsch, da habe ich ja ganz tief ins Klo gegriffen ;=)
Ok, also ^ ist auch bei defines ein XOR. Dachte das betrachtet nur der
Präprozessor und der erkennt ^ als Potenz. Also doch eher math.h
einbinden und pow nutzen? Denn das 2L<<16 = 2 hoch 16 ist, ist mir jetzt
klar, in 2 Wochen evtl. nicht mehr. Deswegen wollte ich ja auch nicht
die 65536 dort stehen haben.
Das der Compiler von links nach rechts rechnet ist ja erwünscht, bzw.
war mir klar. Genau deshalb habe ich erst mal dividiert, damit ich mit
2^32 (unsigned long) auch noch hinkomme.
Den doppelten cast hielt ich für nötig, damit die Rechnung (mit den
großen Zahlen) in unsigned long durchgeführt wird, das Ergebnis wiederum
in ein (unsigned short) passt. Also können beide casts entfallen?
Warum eine Klammer um den ganzen define Ausdruck? Der Präprozessor
sollte doch erst alles ausrechnen und dann zuweisen, oder?
Warum übrigens 2L<<16 und nicht 2UL<<16 (also unsigned, ist ja immer
positiv)?
Muss da mal dringend was drüber lesen...
Danke,
Jan
> müsste es statt 2UL<<16 nicht eher 1UL<<16 heißen?
Richtig. Die Angabe von Falk ist falsch.
> Denn das 2*L<<16 = 2 hoch 16 ist, ist mir jetzt> klar, in 2 Wochen evtl. nicht mehr.
Dann solltest Du das mit dem Programmieren in C vielleicht gleich wieder
sein lassen? Der Shift-Operator gehört zum C-Programmieren wie das Atmen
zum Leben.
*) Natürlich ist 1L<<16 2 hoch 16 und nicht 2L<<16.
Das "L" ist übrigens nur auf 16-Bit-Systemen erforderlich, auf
32-Bit-Systemen kann es entfallen. Das liegt an sizeof (int).
@ Jan Mayer (Gast)
>Präprozessor und der erkennt ^ als Potenz. Also doch eher math.h
Nein, kein math.h.
>einbinden und pow nutzen? Denn das 2L<<16 = 2 hoch 16 ist, ist mir jetzt>klar, in 2 Wochen evtl. nicht mehr. Deswegen wollte ich ja auch nicht
???
Alzheimer?
Das sind Grundlagen!
>Warum eine Klammer um den ganzen define Ausdruck? Der Präprozessor>sollte doch erst alles ausrechnen und dann zuweisen, oder?
Nein, der Präprozessor rechnet gar nicht. Er ersetz nur Text.
#define sum a+b
int x;
x = 5 * sum;
Na, dämmerts?
>Warum übrigens 2L<<16 und nicht 2UL<<16 (also unsigned, ist ja immer>positiv)?
UL geht auch.
>müsste es statt 2UL<<16 nicht eher 1UL<<16 heißen?>Denn sonst würde ja die Bitmaske ...00010 um 16 Stellen geschoben.
Stimmt. Uuuups. Kleiner Aufmerksamkeitstest. ;-)
>Das "L" ist übrigens nur auf 16-Bit-Systemen erforderlich, auf>32-Bit-Systemen kann es entfallen. Das liegt an sizeof (int).
Na aber mit L wirds systemunabhängig wasserdicht. Wer diesem Müll mit
unterschielichen INT Grössen eingeführt hat sollte an die Wand gestellt
werden.
MFg
Falk
> Ok, also ^ ist auch bei defines ein XOR[..]
Nicht nur bei #defines -also dem Präprozessor- sondern in C allgemein. C
kennt keinen Potenzoperator (außer eben << bei der Basis 2). Falls du
die Potenz wirklich mal brauchst, mach es :
a) für ints als Schleife
b) es gibt "double pow(double basis, double exponent)" in der math.h
(nur mit -lm), aber meistens braucht man kein float als Exponenten.
hth. Jörg
Hallo,
so und jetzt bin ich ruhig und werde mich weider meinen C Grundlagen
widmen. Probiere ja gerade erst mal einen Timer "universell" zu machen,
so das man später nur noch Zeit und Prescaler eintragen muss (geht
natürlich nur in den Grenzen des Timers).
Trotzdem: danke.
Gruß,
Jan
> Ok, also ^ ist auch bei defines ein XOR. Dachte das betrachtet nur der> Präprozessor und der erkennt ^ als Potenz.
Wie bist du denn zu dieser Weisheit gelangt?
> Warum eine Klammer um den ganzen define Ausdruck? Der Präprozessor> sollte doch erst alles ausrechnen und dann zuweisen, oder?
Wie kommst du darauf? #define macht nichts weiter als eine
Textersetzung. Eine Art simpler Editor, für den man Anweisungen direkt
in den Code schreibt. Wo immer der Präprozessor ein START findet (außer
natürlich in Stringkonstanten und Kommentaren) ersetzt er es einfach nur
durch (unsigned short) ((unsigned long) F_CPU/65536 * MY_TIME/1000) und
gibt das dann so an den Compiler weiter.