www.mikrocontroller.net

Forum: Compiler & IDEs Potenzen in defines nicht möglich?


Autor: Jan Mayer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe ein kleines Syntaxproblem, bzw. bekomme eine Warnung vom Compiler. 
Folgendes geht ohne Probleme/Warnings:
// Zeit im Klartext
#define MY_TIME      100    // = 100msec

// Zeiten für den uController berechnen (65536 = 2^16 = 16-Bit Timer, kein Prescaler)
#define START        (unsigned short) ((unsigned long) F_CPU/65536 * MY_TIME/1000)

Dies hier (für mich logischer) bringt allerdings eine Warnung:
// Zeit im Klartext
#define MY_TIME      100    // = 100msec

// 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)


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

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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.

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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) ?

Autor: Jan Mayer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Jan Mayer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

noch eine Frage:
müsste es statt 2UL<<16 nicht eher 1UL<<16 heißen?
Denn sonst würde ja die Bitmaske ...00010 um 16 Stellen geschoben.

Gruß,

Jan

Autor: Hmmm... (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Muss da mal dringend was drüber lesen...

Jo

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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).

Autor: Falk Brunner (falk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ 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

Autor: Jörg X. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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

Autor: Jan Mayer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.