#IF mit float Wert im Präprozessor auswerten

Gast #2420964
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
#2421379
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? ;-)
Gast #2421993
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
#2422210
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? ;-)
#2422277
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"?
Gast #2422324
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
#2422334
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.
#2422359
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).
#2422378
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.
Gast #2422472
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
#2422531
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
#2422571
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.
#2422644
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 ;-)
Gast #2422714
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
#2422734
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.
#2424952
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
#2425066
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren