Forum: Compiler & IDEs #IF mit float Wert im Präprozessor auswerten


von D.E. (Gast)


Lesenswert?

Hallo,

ich habe folgendes Problem, ich möchte mit dem Präprozessor auf eine 
bestimmte Bedingung testen, die allerdings float ist.

Der Präprozessor kann allerdings nur integer Rechnung und quittiert dies 
deshalb mit der Fehlermeldung "floating constant in preprocessor 
expression".


Ein Beispiel:
1
#define AVERAGE  12.5  // AVERAGE wird eigentlich vorher ausgerechnet,
2
                       // hier nur zur Vereinfachung als konstanter Wert
3
#define VAL       3
4
5
#if (AVERAGE * VAL > 255)
6
(...)
7
#else
8
(...)
9
#endif

Es kommt zur Fehlermeldung, weil im #if( ) ein float Wert steht.

Gibt es eine Möglichkeit, eine Konvertierung float -> integer 
vorzunehmen?
Die Nachkommastelle von AVERAGE ist unwichtig und könnte abgeschnitten 
werden.

Danke & Grüße

Dirk

von Sam .. (sam1994)


Lesenswert?

Rechne deine Rechnung z.b. mal 1000, so dass kein float rauskommt und 
vergleiche den Wert mit 255000.

von Mark B. (markbrandis)


Lesenswert?

D.E. schrieb:
> Die Nachkommastelle von AVERAGE ist unwichtig und könnte abgeschnitten
> werden.

Na dann... mach das doch?

Ich meine, wie kommt denn der Wert in Deinen Sourcecode rein? Wird da 
eine Sourcecode-Datei von irgend einem Tool autogeneriert? Wenn nicht... 
dann versteh ich die Frage irgendwie nicht so recht. Wer soll denn zum 
Zeitpunkt der Übersetzung einen Wert ausgerechnet haben, von dem der 
weitere Kompiliervorgang abhängt - das zu übersetzende Programm? ;-)

von D.E. (Gast)


Lesenswert?

> Na dann... mach das doch?

AVERAGE wird vorher ausgerechnet, ich habe keinen Einfluss darauf ob und 
wieviele Nachkommastellen entstehen. Die Lösung mit der Multiplikation 
hatte ich auch schon, aber wie gesagt, der Wert wird errechnet, da ist 
die Anzahl der Nachkommastellen nicht vorhersagbar.

>Wer soll denn zum Zeitpunkt der Übersetzung einen Wert ausgerechnet haben

Der Präprozessor, in AVERAGE gehen bei der Berechnung mehrere zur 
Compilierzeit bekannte Größen ein.

Grüße

Dirk

von Peter D. (peda)


Lesenswert?

D.E. schrieb:
> Gibt es eine Möglichkeit, eine Konvertierung float -> integer
> vorzunehmen?

Nein.
Was einmal float war, kann der Präprozessor nicht mehr bestimmen.
Erst der Compliler rechnet einen Cast von float nach int aus.


Peter

von Mark B. (markbrandis)


Lesenswert?

D.E. schrieb:
>>Wer soll denn zum Zeitpunkt der Übersetzung einen Wert ausgerechnet haben
>
> Der Präprozessor, in AVERAGE gehen bei der Berechnung mehrere zur
> Compilierzeit bekannte Größen ein.

Nun, der Präprozessor kennt nur Ganzzahlarithmetik meines Wissens nach.
Beispiel:

1
#define AVERAGE  (125/10)
2
3
printf("AVERAGE = %d\n", AVERAGE);

AVERAGE hat nicht etwa den Wert 12.5 sondern den Wert 12. Eine Ausgabe 
mit %f anstatt %d bringt eine Warnung vom Compiler. Angabe von 125.0 
anstatt 125 oder 10.0 anstatt 10 wird nicht akzeptiert.

Wie soll da ein float bei der Berechnung herauskommen? Ach so, wenn man 
eine der beteiligten Konstanten z.B. als 3.141 definiert und mit dieser 
dann rechnen will.

Eine Möglichkeit: Alles mit einem konstanten Faktor multiplizieren, so 
dass man keine "Gleitkomma-Konstanten" braucht. Samuel K. hat es schon 
vorgeschlagen. Oder wie genau muss es sein? Kommt da als Konstante pi 
auf 15 Stellen genau vor? ;-)

von Mark B. (markbrandis)


Lesenswert?

Irgendwie finde ich diesen Anwendungsfall etwas seltsam, aber vielleicht 
steh ich auch einfach nur auf dem Schlauch. ;-)

von Stefan E. (sternst)


Lesenswert?

Mark Brandis schrieb:
> AVERAGE hat nicht etwa den Wert 12.5 sondern den Wert 12.

Was aber rein gar nichts mit dem Präprozessor zu tun hat.
Der Präprozessor rechnet in solchen Fällen nie selber etwas aus, er 
macht nur Textersetzungen. Er rechnet nur dann selber, wenn er auch 
selber das Ergebnis braucht, also in einer #if-Zeile.

Mark Brandis schrieb:
> Angabe von 125.0
> anstatt 125 oder 10.0 anstatt 10 wird nicht akzeptiert.

Was soll das heißen, "wird nicht akzeptiert"?

von Stefan E. (sternst)


Lesenswert?

D.E. schrieb:
> AVERAGE wird vorher ausgerechnet,

Nein, wird es nicht. (siehe meinen vorigen Post)

Also zeige erst mal, was da nun tatsächlich steht, dann kann man auch 
konkrete Aussagen machen.

von D.E. (Gast)


Lesenswert?

>Nein, wird es nicht. (siehe meinen vorigen Post)

Wie wäre es mal mit einfach glauben, daß in AVERAGE eine Zahl mit 
Nachkommastelle steht. Wo die herkommt ist letztlich irrelevant für die 
Frage.

Aber wenn es hilft:
1
#define LIMIT           Wert1
2
#define UPDATE_INTERVAL Wert2
3
#define NO_OF_SAMPLES   Wert3
4
5
#define AVERAGE  (UPDATE_INTERVAL * LIMIT / NO_OF_SAMPLES)

Wert1, Wert2, Wert3 werden aus anderen durch #define bestimmten Werten 
ebenfalls ausgerechnet.

Letztlich geht es darum, daß jemand, der den Code nicht kennen muss auch 
in der Lage ist Maschinenparameter zu verändern ohne, daß es im C-Code 
zu Fehlern z.B. durch Überläufe kommt.

Grüße


Dirk

von Stefan E. (sternst)


Lesenswert?

D.E. schrieb:
> Wert1, Wert2, Wert3 werden aus anderen durch #define bestimmten Werten
> ebenfalls ausgerechnet.

Nochmal: der Präprozessor rechnet nichts vorher aus, er macht nur 
Textersetzungen. Eine Berechnung findet erst in der #if-Zeile selber 
statt.

Das
1
#define AVERAGE  0.5
2
3
#if ... AVERAGE ...
und das
1
#define A 1
2
#define B 2
3
#define AVERAGE  (A/B)
4
5
#if ... AVERAGE ...
sind zwei komplett unterschiedliche Fälle.
Ersteres funktioniert nicht, letzteres schon (wobei AVERAGE in der 
#if-Zeile zu 0 wird).

Und deshalb ist das
> Wie wäre es mal mit einfach glauben, daß in AVERAGE eine Zahl mit
> Nachkommastelle steht. Wo die herkommt ist letztlich irrelevant für die
> Frage.
Quatsch.

PS: Wenn also auch in deinen anderen defines (Wert1, etc) nirgendwo eine 
float Konstante steht, sehe ich nicht, was jetzt eigentlich dein 
Problem ist.

von D.E. (Gast)


Lesenswert?

Du vergreifst Dich im Ton....

Grüße

D.E.

von Mark B. (markbrandis)


Lesenswert?

Stefan Ernst schrieb:
> Mark Brandis schrieb:
>> Angabe von 125.0
>> anstatt 125 oder 10.0 anstatt 10 wird nicht akzeptiert.
>
> Was soll das heißen, "wird nicht akzeptiert"?
1
#define AVERAGE  (125.0/10)
2
#if (AVERAGE * VAL > 255)

ergibt:
main.c:4:6: floating constant in preprocessor expression
1
#define AVERAGE  (125/10.0)
2
#if (AVERAGE * VAL > 255)

ergibt:
main.c:4:6: floating constant in preprocessor expression
main.c:4:6: division by zero in #if

Zumindest mit gcc Version 3.4.5 unter Windows (MinGW).

von Mark B. (markbrandis)


Lesenswert?

D.E. schrieb:
> Wie wäre es mal mit einfach glauben, daß in AVERAGE eine Zahl mit
> Nachkommastelle steht. Wo die herkommt ist letztlich irrelevant für die
> Frage.

Nein, ist es eben nicht. Wenn Du das nicht verstehen möchtest, können 
wir Dir leider nicht helfen.

von Stefan E. (sternst)


Lesenswert?

Mark Brandis schrieb:
>> Was soll das heißen, "wird nicht akzeptiert"?
1
#define AVERAGE  (125.0/10)
2
#if (AVERAGE * VAL > 255)
>
> ergibt:
> main.c:4:6: floating constant in preprocessor expression

Ja, aber in deinem Beispiel oben steht kein #if...
Da steht
1
printf("AVERAGE = %d\n", AVERAGE);

Und das hier
1
#define AVERAGE  (125.0/10)
2
3
printf("AVERAGE = %f\n", AVERAGE);
würde dir ein 12.5 als Ausgabe liefern. Dein Beispiel oben hat also 
nicht zu tun mit der Frage, ob der Präprozessor selber mit float rechnen 
kann, oder nicht.

von Mark B. (markbrandis)


Lesenswert?

Stefan Ernst schrieb:
> Ja, aber in deinem Beispiel oben steht kein #if...

Ja okay, das kommt davon wenn man durcheinander kommt. ;-)

von Stefan E. (sternst)


Lesenswert?

D.E. schrieb:
> Du vergreifst Dich im Ton....

Ich verstehe. Unabhängig vom fachlichen Inhalt, wird Hilfe von dir nur 
akzeptiert, wenn sie dir zusammen mit viel Zucker in ... nun, belassen 
wir es dabei.
Kein Problem, ich äußere mich zum Thema nicht weiter.

von D.E. (Gast)


Lesenswert?

Peter hatte die Frage bereits ausreichend beantwortet.
Mehr wollte ich nicht wissen.

Peter Dannegger schrieb:
> D.E. schrieb:
>> Gibt es eine Möglichkeit, eine Konvertierung float -> integer
>> vorzunehmen?
>
> Nein.
> Was einmal float war, kann der Präprozessor nicht mehr bestimmen.
> Erst der Compliler rechnet einen Cast von float nach int aus.
>
>
> Peter

Danke nochmal dafür.

Grüße

Dirk

von Karl H. (kbuchegg)


Lesenswert?

D.E. schrieb:
> Peter hatte die Frage bereits ausreichend beantwortet.

Deine Antworten zeigen allerdings, dass du sie nicht in ihrer vollen 
Konsequenz verstanden hast.

Sonst würdest nicht so etwas behaupten

> Wie wäre es mal mit einfach glauben, daß in AVERAGE
> eine Zahl mit Nachkommastelle steht.
>
> #define LIMIT           Wert1
> #define UPDATE_INTERVAL Wert2
> #define NO_OF_SAMPLES   Wert3
>
> #define AVERAGE  (UPDATE_INTERVAL * LIMIT / NO_OF_SAMPLES)

In AVERAGE 'steht' überhaupt keine Zahl, sondern der Text 
"(UPDATE_INTERVAL * LIMIT / NO_OF_SAMPLES)". Das ist ein himmelhoher 
Unterschied.

Im #if wird dieser Text ausgewertet, indem die Textersetzungen 
vorgenommen werden. Der Preprozessor macht als alle Ersetzungen und 
landet bei

    Wert2 * Wert1 / Wert3

und wenn diese Wertn selbst wieder Makros sind, dann wird weiter 
ersetzt, solange bis nichts mehr zu ersetzen ist.

Und erst dann wird dieser Ausdruck ausgewertet und sein Ergebnis wird 
zur Entscheidungsgrundlage vom #if

von (prx) A. K. (prx)


Lesenswert?

Der Präprozessor kann per Sprachdefinition nicht mit Fliesskommazahlen 
rechnen. Konvertieren kann er sie folglich auch nicht. Man darf zwar in 
#define Statements nach Belieben welche reinschreiben, aber sobald diese 
Zahlen direkt oder auf dem Umweg über #define in einem #if Statement 
aufkreuzen ist Schluss.

Wenn sich also die #if Statements aus syntaktischen Gründen nicht durch 
normale C if() Statements ersetzen lassen, dann muss man einen Weg 
finden, die Rechnung ausschliesslich ganzzahlig durchzuführen.

von Mark B. (markbrandis)


Lesenswert?

A. K. schrieb:
> Wenn sich also die #if Statements aus syntaktischen Gründen nicht durch
> normale C if() Statements ersetzen lassen, dann muss man einen Weg
> finden, die Rechnung ausschliesslich ganzzahlig durchzuführen.

Womit wir dann wieder bei der ersten Antwort von Samuel K. wären.

Ich würde ja immer noch gerne einen sinnvollen Anwendungsfall für das 
hier geschilderte Szenario sehen, aber ich glaub das wird nix mehr ;-)

von Sam .. (sam1994)


Lesenswert?

Wobei reine if-Statements auch funktionieren würde. Schließlich 
optimiert der Compiler
1
if(245.6 > 255.0)
 weg.

von D.E. (Gast)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Und erst dann wird dieser Ausdruck ausgewertet und sein Ergebnis wird
> zur Entscheidungsgrundlage vom #if


Es ist mir schon klar, daß der Präprozessor nur Ersetzungen durchführt.
Am Ende steht ein Mathematischer Ausdruck, der im #if Statement 
ausgewertet wird. Vielleicht war die Bezeichnung Wert1... etwas 
ungünstig gewählt, aber ein Wert kann auch einen Ausdruck darstellen.

Worum es mir lediglich ging ist, das am Ende AVERAGE von einer 
erheblichen Anzahl unterschiedlicher Terme abhängig ist und es deshalb 
nicht mehr ganz einfach ist sie so zu definieren, daß keine 
Nachkommastellen entstehen.

Für den C-Code in den nachher der Ausdruck für AVERAGE eingesetzt wird 
ist das schnurz. Es ging mit um die #if Anweisung des Präprozessors.

Mit anderen Worten ich suchte nach einer Möglichkeit im #if auf Zahlen 
mit Nachkommastellen zu testen bzw. einer Präprozessor Anweisung um 
innerhalb des #if statements die Nachkommastellen abzuschneiden.

Wie Peter bereits schrieb gibt es diese Möglichkeit nicht, damit ist die 
Sache erledigt.

Grüße


Dirk

von (prx) A. K. (prx)


Lesenswert?

D.E. schrieb:

> erheblichen Anzahl unterschiedlicher Terme abhängig ist und es deshalb
> nicht mehr ganz einfach ist sie so zu definieren, daß keine
> Nachkommastellen entstehen.

Fliesskommazahlen entstehen nicht, sie werden explizit hingeschrieben. 
Wenn keiner der Ausgangswerte, mit denen gerechnet wird, eine 
Fliesskommazahl ist, dann entsteht auch bei beliebig komplizierter 
Rechnung keine.

Natürlich kann es auf diesem Weg geschehen, dass die Genauigkeit so sehr 
unter die Räder kommt, dass die Rechnung wertlos wird. Das kann man oft 
über die Skalierung der Werte in den Griff kriegen.

von Herbert (Gast)


Lesenswert?

Mark Brandis schrieb:
> Ich würde ja immer noch gerne einen sinnvollen Anwendungsfall für das
> hier geschilderte Szenario sehen, aber ich glaub das wird nix mehr ;-)

Bei der > 255 würde ich mal mit einer Optimierung rechnen. Entweder wird 
in 8Bit oder 16Bit gerechnet.


Grüße.

von Peter D. (peda)


Lesenswert?

Mark Brandis schrieb:
> Ich würde ja immer noch gerne einen sinnvollen Anwendungsfall für das
> hier geschilderte Szenario sehen, aber ich glaub das wird nix mehr ;-)

Och, da gibt es ne Menge.
Z.B. wenn der Baudratenfehler zu groß wird, oder ein Teilerwert nicht 
mehr in das IO-Register paßt, möchte man gerne eine Fehlermeldung 
ausgeben (#error), damit man nicht einen syntaktisch korrekten, aber 
funktional falschen Code erzeugt.

Man kann als Würg-Äround zwar alles auf integer umstellen.
Dann werden die Macros aber deutlich schwerer lesbarer.
Z.B. ein:
1
#define F_CPU 8000000
hat schon oft eine Null zuviel oder zuwenig gehabt.
Bei einem:
1
#define F_CPU 8e6
kann das nicht passieren.


Peter

von Detlef _. (detlef_a)


Lesenswert?

oder so

#define F_CPU (8000*1000)

Cheers
Detlef

von Peter D. (peda)


Lesenswert?

Detlef _a schrieb:
> #define F_CPU (8000*1000)

Dann ist F_CPU == 4608
1
#define F_CPU (8000*1000)
2
  x = F_CPU;
3
  a4:  80 e0         ldi  r24, 0x00  ; 0
4
  a6:  92 e1         ldi  r25, 0x12  ; 18
5
  a8:  a0 e0         ldi  r26, 0x00  ; 0
6
  aa:  b0 e0         ldi  r27, 0x00  ; 0
7
  ac:  80 93 00 01   sts  0x0100, r24
8
  b0:  90 93 01 01   sts  0x0101, r25
9
  b4:  a0 93 02 01   sts  0x0102, r26
10
  b8:  b0 93 03 01   sts  0x0103, r27


Peter

von (prx) A. K. (prx)


Lesenswert?

Peter Dannegger schrieb:

> #define F_CPU 8e6
> kann das nicht passieren.

Dann kannst du im Präprozessor (#if) aber nicht damit rechnen.

von Peter D. (peda)


Lesenswert?

A. K. schrieb:
> Dann kannst du im Präprozessor (#if) aber nicht damit rechnen.

Ja, man kann leider nicht alles haben.
Entweder nicht testbare aber leserliche float Macros ohne 
Überlauf/Unterlauf.
Oder testbare aber unleserliche und fehlerträchtige integer 
Würg-Ärounds.


Peter

von Ralf G. (ralg)


Lesenswert?

Peter Dannegger schrieb:
> Detlef _a schrieb:
>> #define F_CPU (8000*1000)
>
> Dann ist F_CPU == 4608

Wäre ich auch drauf reingefallen. Obwohl völlig logisch (dass das falsch 
wird).
Also:
1
#define F_CPU (8000UL*1000)   // übersichtliche Gruppierung der Tausender

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.