Forum: Compiler & IDEs Präprozessor Frage


von Alex (Gast)


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.
1
#define WISHED_TIME1 (1/100) // seconds
2
3
#if (  ( (F_CPU / 1) * WISHED_TIME1) <= 0x0000FFFFUL)
4
  TCCR1B = _BV(WGM12) | _BV(CS10);
5
#elif (  ( (F_CPU / 8) * WISHED_TIME1) <= 0x0000FFFFUL)
6
  TCCR1B = _BV(WGM12) | _BV(CS11); 
7
#elif (  ( (F_CPU / 64) * WISHED_TIME1) <= 0x0000FFFFUL)
8
  TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10);
9
#elif (  ( (F_CPU /256) * WISHED_TIME1) <= 0x0000FFFFUL)
10
  TCCR1B = _BV(WGM12) | _BV(CS12);
11
#elif (  ( (F_CPU /1024) * WISHED_TIME1) <= 0x0000FFFFUL)
12
  TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10);
13
#else
14
  #error Dont know how to setup timer1
15
#endif
16
#else
17
  #error Dont know how to setup timer1  
18
#endif
19
20
#define IRQ_PER_SEC (1/WISHED_TIME1)
21
22
uint16_t test=IRQ_PER_SEC;
23
float test1= WISHED_TIME1;

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

Schreibe ich
1
#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

von Alex (ein anderer ...) (Gast)


Lesenswert?

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

#define WISHED_TIME1 (0.01f)
                          ^

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.
1
#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:
1
#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.

von Alex (ein anderer ...) (Gast)


Lesenswert?

1
#define FLOAT_1 0.1f
2
#define FLOAT_2 0.1f
3
#define FLOAT_3 (FLOAT_1 * FLOAT_2)
4
5
Int32 main(void)
6
{
7
    float foobar = FLOAT_3;
8
    return 0;
9
}

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Alex #1 (Gast)


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

von Peter D. (peda)


Lesenswert?

Man kann mit float nur rechnen lassen, aber keine Tests durch den 
Präprozessor machen.
1
#include <io.h>
2
3
#define XTAL 11.0592e6
4
5
#define T1_INTERVAL     20e-3           // 20ms
6
7
#define PRESCALE        (XTAL * T1_INTERVAL / 65536.0)
8
9
void test( void )
10
{
11
  TCCR1B = (PRESCALE < 1)   ? 1<<CS10 :
12
           (PRESCALE < 8)   ? 1<<CS11 :
13
           (PRESCALE < 64)  ? 1<<CS10^1<<CS11 :
14
           (PRESCALE < 256) ? 1<<CS12 :
15
                              1<<CS10^1<<CS12;
16
}


Peter

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Simon K. (simon) Benutzerseite


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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...

von Peter D. (peda)


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

von Simon K. (simon) Benutzerseite


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

von Peter D. (peda)


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

von daniel (Gast)


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

von daniel (Gast)


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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.