www.mikrocontroller.net

Forum: Compiler & IDEs Präprozessor Frage


Autor: Alex (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, wollte mir vom Präprozessor eigentlich gemütlich den Vorteiler 
bei ATmega ausrechnen lassen, nur bin ich scheinbar an die Grenze meiner 
Fähigkeiten bzw. Verständnis vom Präprozessor angelangt.
#define WISHED_TIME1 (1/100) // seconds

#if (  ( (F_CPU / 1) * WISHED_TIME1) <= 0x0000FFFFUL)
  TCCR1B = _BV(WGM12) | _BV(CS10);
#elif (  ( (F_CPU / 8) * WISHED_TIME1) <= 0x0000FFFFUL)
  TCCR1B = _BV(WGM12) | _BV(CS11); 
#elif (  ( (F_CPU / 64) * WISHED_TIME1) <= 0x0000FFFFUL)
  TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10);
#elif (  ( (F_CPU /256) * WISHED_TIME1) <= 0x0000FFFFUL)
  TCCR1B = _BV(WGM12) | _BV(CS12);
#elif (  ( (F_CPU /1024) * WISHED_TIME1) <= 0x0000FFFFUL)
  TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10);
#else
  #error Dont know how to setup timer1
#endif
#else
  #error Dont know how to setup timer1  
#endif

#define IRQ_PER_SEC (1/WISHED_TIME1)

uint16_t test=IRQ_PER_SEC;
float test1= WISHED_TIME1;

Leider wird test1 0 zugewiesen und test ergibt dann wegen "division 
durch 0" dann entsprechend 0xFFFF.

Schreibe ich
#define WISHED_TIME1 (0.01)
bricht er gleich mit
../timer1.c:30:23: error: floating constant in preprocessor expression
ab.

Danke schonmal im Voraus - Alex

Autor: Alex (ein anderer ...) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Per default interpretiert die Präprozessor jede Zahlenkombination als 
integer, es sei denn du sagst ihm was anderes.

#define WISHED_TIME1 (0.01f)
                          ^

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alex (ein anderer ...) wrote:

> Per default interpretiert die Präprozessor jede Zahlenkombination als
> integer, es sei denn du sagst ihm was anderes.

Der Präprozessor kann ausschließlich Integer-Rechnung.

> #define WISHED_TIME1 (0.01f)

Was soll'n das für eine Sprache sein?  C jedenfalls nicht.

Alex (#1), bedenke, dass der Präprozessor in allererster Linie Makros
ersetzt.  Dein (1/100) wird also genau so in die entsprechenden
Ausdrücke eingesetzt.  Falls ein Ausdruck innerhalb eines #if auftaucht,
wird er nach normalen Integerregeln berechnet.
#elif (  ( (F_CPU / 8) * WISHED_TIME1) <= 0x0000FFFFUL)

ergibt also (mal F_CPU = 1000000ul angenommen)

(  ( (1000000ul / 8) * (1/100)) <= 0x000FFFFUL)

Da du das 1/100 geklammert hast, muss dieser Teilausdruck immer zuerst
berechnet werden, und ergibt letztlich (Integer-Rechnung) die Konstante
0.  Das ist sicher nicht, was du wolltest. ;-)

Lässt du die Klammern weg:
#define WISHED_TIME1 1/100

so ergibt die Ersetzung:

(  ( (1000000ul / 8) * 1/100) <= 0x000FFFFUL)

In diesem Falle wird zuerst 1000000ul / 8 berechnet (ergibt 125000ul),
danach mit 1 multipliziert (immer noch 125000ul), dann durch 100
dividiert (12500ul), dann verglichen.  Sieht mir eher nach dem aus,
was du erreichen wolltest, nicht wahr?  Natürlich ist das ziemlich
riskant, mit solchen ungeklammerten Ausdrücken bewusst die
Auswertungsreihenfolge zu ändern, ist aber bei Integer-Rechnung deine
einzige Chance (wenn du nicht gerade Zähler und Nenner in separate
Makros legen willst).

OT: "wished" sollte in diesem Zusammenhang besser "desired" heißen.
Die Amis würden es aber wohl eher TARGET_TIME1 nennen.

Autor: Alex (ein anderer ...) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
#define FLOAT_1 0.1f
#define FLOAT_2 0.1f
#define FLOAT_3 (FLOAT_1 * FLOAT_2)

Int32 main(void)
{
    float foobar = FLOAT_3;
    return 0;
}

Mein g++ sorgt dafür, dass in foobar der Wert 0.01 landet ...

Hier rechnet dann wohl der Compiler für mich?

Wäre ein Compiler dann auch in der Lage ein (if - else if - else) 
Kontrukt in dessen bedingten Ausdrücken nur Compile-Zeit Konstanten 
verwendet werden aufzulösen (wegzuoptimieren)?

Dann könnte man den Präprozessor komplett aus dem Spiel lassen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Alex (ein anderer ...) wrote:

> Mein g++ sorgt dafür, dass in foobar der Wert 0.01 landet ...

Sorry, dass 0.01f kein gültiges C sei, nehme ich hiermit zurück.
Da man das Feature nur äußerst selten braucht, hatte ich den Suffix
f für die Unterscheidung zwischen float- und double-Konstanten
einfach vergessen.  0.01 ist double, 0.01f ist float.

> Hier rechnet dann wohl der Compiler für mich?

Ja.

> Wäre ein Compiler dann auch in der Lage ein (if - else if - else)
> Kontrukt in dessen bedingten Ausdrücken nur Compile-Zeit Konstanten
> verwendet werden aufzulösen (wegzuoptimieren)?

Wenn du die Optimierung einschaltest, ja.

> Dann könnte man den Präprozessor komplett aus dem Spiel lassen.

Ja, für solche Fälle kann man sie aus dem Spiel lassen.  Andererseits
lassens sich mit Präprozessor-Konstruktionen oft bestimmte Dinge in
Headerfiles gut abstrahieren, sodass sie dann nicht den eigentlichen
Code mit totem Code ,,verschandeln''.  Dadurch kann die Übersichtlich-
keit besser werden.

Autor: Alex #1 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke erstmal fuer die Antworten, das der Praeprozessor nur integer 
Rechnen kann war mir nicht bewusst und damit ist mir nun auch klar waran 
es haengt. Klammer weglassen waere wirklich die schlechteste Loesung, 
daher werde ich wohl eher versuchen die TARGET_TIME1 :) in ms 
auszudruecken und  zukuenftig auch bei Praeprozessor Rechnungen 
Rundungseffekte mit bedenken. Andere Variante waere sicherlich das 
"normal" in Variablen rechnen zu lassen und dann den Compiler zu nutzen 
um dies wegzuoptimieren. Fuer mich ist die bewusste 
Compilerwegoptimierung doch noch etwas undurchsichtig. Ich habe mich 
bisher damit noch nicht so intensiv auseinandergesetzt, um im Vorfeld zu 
wissen was der Compiler in welche Stufe alles wegoptimiert. 
Optimierungen sehe ich fuer mich momentan eher um gut lesbaren und 
verstaendlichen Code schreiben zu koennen und trotzdem Groessen und 
Geschwindigkeitsmaessig etwas mithalten zu koennen.

Gruss Alex

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man kann mit float nur rechnen lassen, aber keine Tests durch den 
Präprozessor machen.
#include <io.h>

#define XTAL 11.0592e6

#define T1_INTERVAL     20e-3           // 20ms

#define PRESCALE        (XTAL * T1_INTERVAL / 65536.0)

void test( void )
{
  TCCR1B = (PRESCALE < 1)   ? 1<<CS10 :
           (PRESCALE < 8)   ? 1<<CS11 :
           (PRESCALE < 64)  ? 1<<CS10^1<<CS11 :
           (PRESCALE < 256) ? 1<<CS12 :
                              1<<CS10^1<<CS12;
}


Peter

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger wrote:

> Man kann mit float nur rechnen lassen, aber keine Tests durch den
> Präprozessor machen.

Die Rechnung erledigt aber der Compiler.  Es ist ein weit verbreiteter
Irrtum, dass der Präprozessor die Konstanten-Eliminierung vornehmen
würde, nur weil man die Konstanten gerade in einem Präprozessormakro
hinterlegt hätte.

Der Präprozessor ersetzt Texte, sonst macht er (fast) nichts.
Eigene Ausdrücke berechnet er nur in einem #if-Test.

Der Name des Headerfiles ist übrigens seit mehr als 5 Jahren
<avr/io.h>, und der Wrapper <io.h> existiert bereits seit 3 Jahren
nicht mehr.  Peter, deine ,,Altmodigkeit'' in allen Ehren, aber bitte
empfehle Leuten, die hier unbedarft rangehen nichts, was nur in deinem
auf steinzeitliche Rückwärtskompatibilität getrimmten Setup 
funktioniert.

Die Benutzung von xor zum Verknüpfen der Vorteilerbits bzw. der Vorteil
gegenüber dem (einschließlichen) oder erschließt sich mir ganz und gar
nicht.

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Peter Dannegger wrote:
>
>> Man kann mit float nur rechnen lassen, aber keine Tests durch den
>> Präprozessor machen.
>
> Die Rechnung erledigt aber der Compiler.

Ich denke, dass er das meinte... ;)
Zumindest kann ich mir nichts anderes vorstellen.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Küppers wrote:

> Ich denke, dass er das meinte... ;)

Ja, wenn ich mir's nochmal durchlese, wirst du wohl Recht haben.  Aber
irgendwie so seltsam formuliert, dass ich es beim ersten Lesen wohl
nicht wirklich geschnallt habe...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:

> Die Benutzung von xor zum Verknüpfen der Vorteilerbits bzw. der Vorteil
> gegenüber dem (einschließlichen) oder erschließt sich mir ganz und gar
> nicht.

Das ^ läßt sich leichter tippen, man muß nicht 2 weit entfernte Tasten 
drücken (AltGr rechts, | links).


Die obigen Berechnungen werden sogar bei -O0 zusammengefaßt.


Peter

Autor: Simon K. (simon) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger wrote:
> Jörg Wunsch wrote:
>
>> Die Benutzung von xor zum Verknüpfen der Vorteilerbits bzw. der Vorteil
>> gegenüber dem (einschließlichen) oder erschließt sich mir ganz und gar
>> nicht.
>
> Das ^ läßt sich leichter tippen, man muß nicht 2 weit entfernte Tasten
> drücken (AltGr rechts, | links).

Peter, ist das dein Ernst? ... *räusper

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Simon Küppers wrote:

>> Das ^ läßt sich leichter tippen, man muß nicht 2 weit entfernte Tasten
>> drücken (AltGr rechts, | links).
>
> Peter, ist das dein Ernst? ... *räusper

Vollster ernst, warum soll man denn keine Tipparbeit sparen?

Das "avr\" spare ich mir ja auch.


Peter

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in c++ sind ja in den templates auch floating point
ausdrücke verboten. wenn ich mich richtig erinnere
war die begründung, dass je nach compiler/maschine
die compile time berechnungen anders ausfallen würden.
man denke auch an die crosscompilationen.
Bei den #define makros meine ich, dass die floating
point berechnungen zur runtime ausgeführt werden.
All die makros würden per textersetzung einfach
eingesetzt und fertig.

gruss, daniel

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
man denke auch an die crosscompilationen.

damit meine ich, dass die maschine auf der compiler läuft,
anders fliesskommazahlen berechnet als die maschine
auf der complierte code später abläuft.

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.