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
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? ;-)
> 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
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
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? ;-)
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"?
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.
>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
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.
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).
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.
>> 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.
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.
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
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
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.
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 ;-)
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
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.
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.
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:
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
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