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


von Erik S. (erik_s)


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.
1
#if PRESCALER_CALC == 1
2
    #define PRESCALER  1
3
    #define PRESCALER_MASK  (1<<CS00)
4
5
  #elif PRESCALER_CALC < 9
6
    #define PRESCALER  8
7
    #define PRESCALER_MASK  (1<<CS01)
8
9
  #elif PRESCALER_CALC < 65
10
    #define PRESCALER  64
11
    #define PRESCALER_MASK  (1<<CS01)|(1<<CS00)
12
13
  #elif PRESCALER_CALC < 257
14
    #define PRESCALER  256
15
    #define PRESCALER_MASK  (1<<CS03)
16
17
  #elif PRESCALER_CALC < 1025
18
    #define PRESCALER  1024
19
    #define PRESCALER_MASK  (1<<CS02)|(1<<CS00)
20
21
  #else 
22
    #error "Timerparameter nicht berechenbar"
23
#endif
24
#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

von Sven P. (Gast)


Lesenswert?

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

von Peter (Gast)


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.

von Erik S. (erik_s)


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.

von Sven P. (Gast)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


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

von Oliver (Gast)


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

von Oliver (Gast)


Lesenswert?

Hilfreich ist bei solchen Makrso, auc abzuprüfen, ob alle erforderlichen 
Defines auch exsitieren.
1
#ifndef PRESCALER_CALC
2
#error "Fehler: PRESCALER_CALC ist nicht definiert"
3
#else
4
#ifndef OSC
5
#error "Fehler: OSC ist nicht definiert"
6
#else
7
...
8
#endif
9
#endif

Oliver

von Erik S. (erik_s)


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:
1
// PRESCALER    gewählter Vorteiler
2
// PRESCALER_MASK  Bitmaske für CS20...CS00 in TCCR0B
3
#define TIMEBASE       10                // TIM0OVF-Intervall in ms
4
5
#define PRESCALER_CALC    (((TIMEBASE * OSC)/256)/1000)  // berechneter minimaler Vorteiler
6
#define OSC          8000000
7
8
#ifndef PRESCALER_CALC
9
  #error "Fehler: PRESCALER_CALC ist nicht definiert"
10
#else
11
  #ifndef OSC
12
    #error "Fehler: OSC ist nicht definiert"
13
  #else
14
    #ifndef TIMEBASE
15
      #error "Fehler: TIMEBASE ist nicht definiert"
16
    #endif
17
  #endif
18
#endif
19
20
#if PRESCALER_CALC == 1
21
    #define PRESCALER  1
22
    #define PRESCALER_MASK  (1<<CS00)*/
23
  #elif PRESCALER_CALC < 9
24
    #define PRESCALER  8
25
    #define PRESCALER_MASK  (1<<CS01)
26
  #elif PRESCALER_CALC < 65
27
    #define PRESCALER  64
28
    #define PRESCALER_MASK  (1<<CS01)|(1<<CS00)
29
  #elif PRESCALER_CALC < 257
30
    #define PRESCALER  256
31
    #define PRESCALER_MASK  (1<<CS03)
32
  #elif PRESCALER_CALC < 1025
33
    #define PRESCALER  1024
34
    #define PRESCALER_MASK  (1<<CS02)|(1<<CS00)
35
  #else 
36
    #error "Timerparameter nicht berechenbar"
37
#endif
38
39
#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)



Obiger Code ergibt im main.i die gewünschten Parameter:
1
# 15 "../main.h"
2
#define TIMEBASE 10
3
4
#define PRESCALER_CALC (((TIMEBASE * OSC)/256)/1000)
5
#define OSC 8000000
6
# 45 "../main.h"
7
#define PRESCALER 1024
8
#define PRESCALER_MASK (1<<CS02)|(1<<CS00)
9
10
11
12
13
#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:
1
// PRESCALER    gewählter Vorteiler
2
// PRESCALER_MASK  Bitmaske für CS20...CS00 in TCCR0B
3
//#define TIMEBASE       10                // TIM0OVF-Intervall in ms
4
5
#define PRESCALER_CALC    (((TIMEBASE * OSC)/256)/1000)  // berechneter minimaler Vorteiler
6
#define OSC          8000000
7
/*
8
#ifndef PRESCALER_CALC
9
  #error "Fehler: PRESCALER_CALC ist nicht definiert"
10
#else
11
  #ifndef OSC
12
    #error "Fehler: OSC ist nicht definiert"
13
  #else
14
    #ifndef TIMEBASE
15
      #error "Fehler: TIMEBASE ist nicht definiert"
16
    #endif
17
  #endif
18
#endif
19
*/
20
#if PRESCALER_CALC == 1
21
    #define PRESCALER  1
22
    #define PRESCALER_MASK  (1<<CS00)*/
23
  #elif PRESCALER_CALC < 9
24
    #define PRESCALER  8
25
    #define PRESCALER_MASK  (1<<CS01)
26
  #elif PRESCALER_CALC < 65
27
    #define PRESCALER  64
28
    #define PRESCALER_MASK  (1<<CS01)|(1<<CS00)
29
  #elif PRESCALER_CALC < 257
30
    #define PRESCALER  256
31
    #define PRESCALER_MASK  (1<<CS03)
32
  #elif PRESCALER_CALC < 1025
33
    #define PRESCALER  1024
34
    #define PRESCALER_MASK  (1<<CS02)|(1<<CS00)
35
  #else 
36
    #error "Timerparameter nicht berechenbar"
37
#endif
38
39
#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)
40
#define TIMEBASE       10




und das ergibt im main.i
1
# 17 "../main.h"
2
#define PRESCALER_CALC (((TIMEBASE * OSC)/256)/1000)
3
#define OSC 8000000
4
# 36 "../main.h"
5
#define PRESCALER 8
6
#define PRESCALER_MASK (1<<CS01)
7
# 51 "../main.h"
8
#define OCR_PRESET (unsigned char)((TIMEBASE * OSC) / PRESCALER/1000)
9
#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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Oliver (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver schrieb:

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

Nein:
1
% cat foo.c
2
#if TIMEBASE > 0
3
#  define FOO 42
4
#else
5
#  define FOO 23
6
#endif
7
8
#define TIMEBASE 42
9
10
TIMEBASE;
11
FOO;
12
% cc -E foo.c
13
# 1 "foo.c"
14
# 1 "<built-in>"
15
# 1 "<command line>"
16
# 1 "foo.c"
17
# 9 "foo.c"
18
42;
19
23;

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

von Oliver (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Oliver schrieb:

> TIMEBASE steht nicht innerhalb des #if.

Mea culpa.  ETOOMANYLINESWITHMACROS :)

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.