www.mikrocontroller.net

Forum: Compiler & IDEs #if funktioniert nur in *.c, nicht in *.h - Grund?


Autor: Erik S. (erik_s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forengemeinde,

Ich habe da ein "Problem": Der unten stehende Code soll mir 
selbstständig die Einstellparameter für den Timer berechnen bzw. 
auswählen.
#if PRESCALER_CALC == 1
    #define PRESCALER  1
    #define PRESCALER_MASK  (1<<CS00)

  #elif PRESCALER_CALC < 9
    #define PRESCALER  8
    #define PRESCALER_MASK  (1<<CS01)

  #elif PRESCALER_CALC < 65
    #define PRESCALER  64
    #define PRESCALER_MASK  (1<<CS01)|(1<<CS00)

  #elif PRESCALER_CALC < 257
    #define PRESCALER  256
    #define PRESCALER_MASK  (1<<CS03)

  #elif PRESCALER_CALC < 1025
    #define PRESCALER  1024
    #define PRESCALER_MASK  (1<<CS02)|(1<<CS00)

  #else 
    #error "Timerparameter nicht berechenbar"
#endif
#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)

Das funktioniert an sich auch, aber leider auschschließlich dann, wenn 
der Code im C-File steht, egal ob im Kopf oder in der main(). Platziere 
ich ihn im Header-File, funktioniert die Fallunterscheidung nicht und es 
wird immer der 1. Fall abgearbeitet.
Zwar kann ich mit diesem Umstand ohne weiteres leben, aber es wundert 
mich doch, zumal die #define in allen Varianten im Header-File stehen 
und machen, was sie sollen. Wo liegt also der (Denk-)Fehler?

PS: Ich verwende WinAVR-20071221

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der Denkfehler ist, zu glauben, dass man anhand eines solchen 
nichtssagenden Quelltextfetzens das Problem beurteilen könnte.

Autor: Peter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die Frage ist an welcher stelle PRESCALER_CALC definiert wird, die 
header datei wir ja mit Import einfach in die C datei eingefügt - also 
ist der Code ja zum schluss in der C-Datei. Damit kann es sich nicht 
unterschiedlich verhalten.

Ich vermute du Definierst PRESCALER_CALC nach dem import.

Autor: Erik S. (erik_s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Peter, deine Vermutung war fast richig. #define TIMEBASE war im 
Header-File unter die Fallunterscheidung gerutscht, war mir trotz 
mehrfacher Kontrolle entgangen. Gemeinerweise wurde das auch beim 
Kompilieren nicht bemerkt.

Autor: Sven P. (haku) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übersetz das mal mit '-Wall', dann dürfte es Meldungen geben.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übersetze mit -g3 -save-temps und schau ins Precompilat (.i oder .ii)

Dort siehst du, wann, wie und von wem (GCC-Builtin, cmd-Line, h-Datei, 
...) welches Makro definiert wird.

Johann

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>#define TIMEBASE war im
>Header-File unter die Fallunterscheidung gerutscht,

was eigentlich völlig (l)egal ist. Wichtig ist nur, daß PRESCALER_CALC 
an der richtigen Stelle definiert ist. Wenn das vor deinem 
Codeausschnitt von oben nicht bekannt ist, gibt es eine Warnung, und es 
wird der 2. Fall (PRESCALER_CALC <9) ausgeführt, aber niemals der erste.

Was du schreibst, passt irgendwie alles nicht.

Oliver

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hilfreich ist bei solchen Makrso, auc abzuprüfen, ob alle erforderlichen 
Defines auch exsitieren.
#ifndef PRESCALER_CALC
#error "Fehler: PRESCALER_CALC ist nicht definiert"
#else
#ifndef OSC
#error "Fehler: OSC ist nicht definiert"
#else
...
#endif
#endif

Oliver

Autor: Erik S. (erik_s)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zuerst einmal ein Dankeschön an alle!

@Sven P.: -Wall war durchgängig angeschaltet, hat aber trotzdem in dem 
Fall nicht gewarnt.

@ Johann L.: Danke für den Tipp, werde ich mir merken!

@Oliver: Die Reihenfolge SOLLTE egal sein, ist es anscheinend aber bei 
#if nicht. Ich habe dasselbe Phänomen auf einem anderen Rechner mit 
anderem Betriebssystem und neuerem WINAVR 1:1 reproduziert. Während beim 
normalen Compilieren keine Warnung erscheint, funktioniert die auf 
deinen Rat hin geschriebene Definitionsabfrage hervorragend!

Ich habe den kompletten Code nun wieder in main.h ausgelagert:
// PRESCALER    gewählter Vorteiler
// PRESCALER_MASK  Bitmaske für CS20...CS00 in TCCR0B
#define TIMEBASE       10                // TIM0OVF-Intervall in ms

#define PRESCALER_CALC    (((TIMEBASE * OSC)/256)/1000)  // berechneter minimaler Vorteiler
#define OSC          8000000

#ifndef PRESCALER_CALC
  #error "Fehler: PRESCALER_CALC ist nicht definiert"
#else
  #ifndef OSC
    #error "Fehler: OSC ist nicht definiert"
  #else
    #ifndef TIMEBASE
      #error "Fehler: TIMEBASE ist nicht definiert"
    #endif
  #endif
#endif

#if PRESCALER_CALC == 1
    #define PRESCALER  1
    #define PRESCALER_MASK  (1<<CS00)*/
  #elif PRESCALER_CALC < 9
    #define PRESCALER  8
    #define PRESCALER_MASK  (1<<CS01)
  #elif PRESCALER_CALC < 65
    #define PRESCALER  64
    #define PRESCALER_MASK  (1<<CS01)|(1<<CS00)
  #elif PRESCALER_CALC < 257
    #define PRESCALER  256
    #define PRESCALER_MASK  (1<<CS03)
  #elif PRESCALER_CALC < 1025
    #define PRESCALER  1024
    #define PRESCALER_MASK  (1<<CS02)|(1<<CS00)
  #else 
    #error "Timerparameter nicht berechenbar"
#endif

#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)



Obiger Code ergibt im main.i die gewünschten Parameter:
# 15 "../main.h"
#define TIMEBASE 10

#define PRESCALER_CALC (((TIMEBASE * OSC)/256)/1000)
#define OSC 8000000
# 45 "../main.h"
#define PRESCALER 1024
#define PRESCALER_MASK (1<<CS02)|(1<<CS00)




#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)






Nun das ganze nochmal mit deaktivierter eigener Definitionsabfrage (die 
schlägt so nämlich an).

In main.h steht jetzt:
// PRESCALER    gewählter Vorteiler
// PRESCALER_MASK  Bitmaske für CS20...CS00 in TCCR0B
//#define TIMEBASE       10                // TIM0OVF-Intervall in ms

#define PRESCALER_CALC    (((TIMEBASE * OSC)/256)/1000)  // berechneter minimaler Vorteiler
#define OSC          8000000
/*
#ifndef PRESCALER_CALC
  #error "Fehler: PRESCALER_CALC ist nicht definiert"
#else
  #ifndef OSC
    #error "Fehler: OSC ist nicht definiert"
  #else
    #ifndef TIMEBASE
      #error "Fehler: TIMEBASE ist nicht definiert"
    #endif
  #endif
#endif
*/
#if PRESCALER_CALC == 1
    #define PRESCALER  1
    #define PRESCALER_MASK  (1<<CS00)*/
  #elif PRESCALER_CALC < 9
    #define PRESCALER  8
    #define PRESCALER_MASK  (1<<CS01)
  #elif PRESCALER_CALC < 65
    #define PRESCALER  64
    #define PRESCALER_MASK  (1<<CS01)|(1<<CS00)
  #elif PRESCALER_CALC < 257
    #define PRESCALER  256
    #define PRESCALER_MASK  (1<<CS03)
  #elif PRESCALER_CALC < 1025
    #define PRESCALER  1024
    #define PRESCALER_MASK  (1<<CS02)|(1<<CS00)
  #else 
    #error "Timerparameter nicht berechenbar"
#endif

#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)
#define TIMEBASE       10




und das ergibt im main.i
# 17 "../main.h"
#define PRESCALER_CALC (((TIMEBASE * OSC)/256)/1000)
#define OSC 8000000
# 36 "../main.h"
#define PRESCALER 8
#define PRESCALER_MASK (1<<CS01)
# 51 "../main.h"
#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)
#define TIMEBASE 10

Also wird für TIMEBASE 0 eingesetzt und damit weitergerechnet. Nachdem 
die #if-Sequenz abgearbeitet ist, ist TIMEBASE dann trotzdem der 
richtige Wert.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Erik S. schrieb:

> @Sven P.: -Wall war durchgängig angeschaltet, hat aber trotzdem in dem
> Fall nicht gewarnt.

-Wundef

foo.c:1:5: warning: "FOO" is not defined

> Also wird für TIMEBASE 0 eingesetzt und damit weitergerechnet. Nachdem
> die #if-Sequenz abgearbeitet ist, ist TIMEBASE dann trotzdem der
> richtige Wert.

Ja, so muss es auch sein.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Also wird für TIMEBASE 0 eingesetzt und damit weitergerechnet. Nachdem
>die #if-Sequenz abgearbeitet ist, ist TIMEBASE dann trotzdem der
>richtige Wert.

Das ist zwar richtig, aber in diesem Fall egal.

Gerechnet wird mit TIMEBASE erst bei der Verwendung des Makros 
OCR_PRESET, nicht bei dessen Definition, und da hat es dann den 
richtigen Wert. Daher gibt es für TIMEBASE auch keine Warnung.

Probier die verschiedenen Varianten aus, und schau dir an, was der 
Präprozessor draus macht.

Oliver

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:

> Gerechnet wird mit TIMEBASE erst bei der Verwendung des Makros
> OCR_PRESET, ...

Nein:
% cat foo.c
#if TIMEBASE > 0
#  define FOO 42
#else
#  define FOO 23
#endif

#define TIMEBASE 42

TIMEBASE;
FOO;
% cc -E foo.c
# 1 "foo.c"
# 1 "<built-in>"
# 1 "<command line>"
# 1 "foo.c"
# 9 "foo.c"
42;
23;

Ein Makro innerhalb eines #if wird mit dem Wert bewertet, den er
zu dem Zeitpunkt besitzt, an dem das #if geparst wird.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ein Makro innerhalb eines #if wird mit dem Wert bewertet, den er
>zu dem Zeitpunkt besitzt, an dem das #if geparst wird.

Jaaa - aber davon rede ich doch die ganze Zeit:

TIMEBASE steht nicht innerhalb des #if.

Oliver

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:

> TIMEBASE steht nicht innerhalb des #if.

Mea culpa.  ETOOMANYLINESWITHMACROS :)

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.