www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Präprozessor Verständnis


Autor: elGasto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

Ich habe eine solche Präprozessor-Anweisung geschrieben:
#define LUT_FACTOR(s32)   ((TABLE_SIZE-1) / (3.141592654/2)*ONE + 0.5)

Das Programm enthält später den richtigen Wert, das hab ich überprüft.

Aber wo genau wird dieser Wert berechnet? Der Präprozessor fügt nur 
stumpf ein, soweit ich das verstanden habe und übergibt Rechnungen an 
den Compiler.
Dann verstehe ich allerdings nicht warum man #error bei bestimmten 
Werten erzeugen kann, schließlich wird der Präprozessor nur einmal ganz 
am Anfang aufgerufen.

Wie genau rechnet der Präprozessor/Compiler, bzw. wie genau kann man 
z.B. Pi angeben? Sind das floats? Was für welche?

Darüber hinaus würde ich gerne sicher gehen, dass die Rechnung nicht 
womöglich in meinem uC (zur Laufzeit) ausgeführt wird, aber ich schätze 
da brauche ich mir keine Sorgen zu machen, oder?

Viele Grüße

Autor: Timmo H. (masterfx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Präprozessor fügt einfach nur den Text ein.
Der Compiler optimiert es dann so, dass die Berechnungen schon vorher 
gemacht werden und im Quellcode dann nur noch eine Konstante steht, 
damit das nicht zu lLaufzeit passiert.

Beispiel:
#define TEST(x) 1024/4 + 10*(x)

Im Quellcode wird TEST(10) also durch 1024/4 + 10*(10) ersetzt

Der Compilier sieht, dass es alles Konstanten sind und macht daraus den 
Wert 356.
#define TEST(x) 1024/4 + 10*(x)

int main(){
  int a;
  a = TEST(10);
}

wird zu
int main(){
  int a;
  a = 356;
}

Autor: yalu (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Aber wo genau wird dieser Wert berechnet? Der Präprozessor fügt nur
> stumpf ein, soweit ich das verstanden habe und übergibt Rechnungen an
> den Compiler.

Es gibt einen Fall, wo auch der Präprozessor rechnet, nämlich in
#if-Direktiven. Aber auch dort wird nur mit Integer und nicht mit
Float-Zahlen gerechnet. Die #error-Ausgabe steht meistens in einem
#if-Block. In allen anderen Fällen macht der Präprozessor nur
Textexpansion. Für die Auswertung konstanter Ausdrücke ist dann der
Compiler zuständig.

> Wie genau rechnet der Präprozessor/Compiler, bzw. wie genau kann man
> z.B. Pi angeben? Sind das floats? Was für welche?

Präprozessor: s.o.

Compiler: Die Genauigkeit ist die gleiche wie später bei der Ausführung
des fertigen Programms auf dem Zielsystem. Gleitkommakonstanten sind
defaultmäßig vom Typ double. Auf dem PC ist das double 64 Bit groß, auf
dem AVR nur 32 Bit. Entsprechend berechnet der PC-GCC konstante
Ausdrücke genauer als der AVR-GCC, selbst wenn dieser auf dem gleichen
PC installiert ist. Maßgeblich für die Genauigkeit ist also immer das
Zielsystem und nicht der Rechner auf dem kompiliert wird.

> Darüber hinaus würde ich gerne sicher gehen, dass die Rechnung nicht
> womöglich in meinem uC (zur Laufzeit) ausgeführt wird, aber ich schätze
> da brauche ich mir keine Sorgen zu machen, oder?

Wenn Ausdrücke oder Teilausdrücke ohne Umformung des Terms als konstant
erkannt werden können, werden sie praktisch von jedem Compiler zur
Compilezeit ausgerechnet und das auch ohne eingeschaltete Optimierung.
Der Compiler tut dies, weil er in bestimmten Fällen konstante Ausdrücke
ohne auswerten muss, bspw. in

  int array[5*4+1];

Da bedeutet es für den Compilerentwickler keinen großen Zusatzaufwand,
diese Form der Auswertung auf alle Ausdrücke anzuwenden. Viele
Compiler können zusätzlich einfache Umformungen vornehmen, um dadurch
noch größere Teile von Ausdrücken vorab auswerten zu könenn, darauf
würde ich mich aber nicht verlassen.

Beispiele:

Folgendes sollte praktisch jeder Compiler können:

  a=3+4*5;      ->   a=23;
  a=1+2+x;      ->   a=3+x;
  a=x*(1+2)     ->   a=x*3;

Folgendes können viele, aber möglicherweise nicht alle, da dazu die
Operanden umgestellt werden müssen.

  a=2-(x+1);    ->   a=1-x;

Folgendes kann möglicherweise ebenfalls nicht jeder:

  a=x+1+2;      ->   a=x+3;

Der Ausdruck ist gleichbedeutend mit (x+1)+2, es gibt also keine
konstanten Teilausdrücke. Besser macht man die Umformung selber und
schreibt:

  a=x+(1+2);     oder    a=1+2+x;

Dies sollte wiederum von jedem Compiler in x+3 umgesetzt werden können.

Jeder Teilausdruck in diesen Beispielen kann natürlich auch durch einen
entsprechenden Präprozessormakroaufruf ersetzt werden, also könnte das
erste Beiepiel auch so lauten:

  #define ZWANZIG (4*5)
  a = 3+ZWANZIG;

Wichtig ist, dass in der Makrodefinition die Ausdrücke immer in Klammern
gesetzt sind (wie in (4*5) ). Zum einen können ohne die Klammern bei der
Expansion falsche Ergebnisse entstehen, zum anderen kann der Compiler so
am leichtesten erkennen, dass der Ausdruck konstant ist, auch dann, wenn
er als Teilausdruck eines größeren Ausdrucks auftaucht.

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.