Forum: Compiler & IDEs Präprozessorabfrage


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
ich habe folgenden code:
1
#define dsz_port    D
2
#define dsz_pin     5
3
#define dsz_int_port     2
4
5
6
7
8
#ifdef PORTA //m644
9
10
#else //m328
11
12
#if dsz_port==B
13
#define dsz_vect   PCINT0_vect
14
15
test //gewollte Fehlermeldung wenn diese Stelle erreicht wird
16
#endif
17
18
#endif

ich will mittels glue das PCINT-Register je nach Port-Register 
automatisch zuweisen.

Die Abfrage '#if dsz_port==B' funktioniert jedoch nicht. Obwohl 
dsz_port==D  ist, wird  '#if dsz_port==B' angesprungen.

Was mache ich falsch?

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Wo ist D definiert, und wo B?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
gute Frage. D ist der Buchstabe D. Er wird nur für den GLUE-Macro 
benötigt

#define PORT(x)         GLUE(PORT, x)
#define PIN(x)          GLUE(PIN, x)
#define DDR(x)          GLUE(DDR, x)

und müsste eigentlich den ASCII-Wert 69 darstellen.

von Theor (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Zeichenkonstanten werden mit Apostrophen umgeben. Also etwa 'A', 'B', 
'1' usw.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
das hatte ich probiert.


#if dsz_port=='B'
#define dsz_vect   PCINT0_vect
#endif
#if dsz_port=='C'
#define dsz_vect   PCINT1_vect
#endif
#if dsz_port=='D'
#define dsz_vect   PCINT2_vect
#endif


geht auch nicht.

von lalala (Gast)


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> das hatte ich probiert.
>
> #if dsz_port=='B'
> #define dsz_vect   PCINT0_vect
> #endif
> #if dsz_port=='C'
> #define dsz_vect   PCINT1_vect
> #endif
> #if dsz_port=='D'
> #define dsz_vect   PCINT2_vect
> #endif
>
> geht auch nicht.

sollte aber. Wie testest du, ob es funktioniert?

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
> was mach ich falsch?
1. den AVR erkennt man nicht am Vorgandensein von PORTA, denn den hat 
auch ein Tiny24
2.
1
#if    defined( __AVR_ATmega644__ )
2
  #define DSZ_VECT   PCINT0_vect
3
  #define DSZ_PORT   PORTA
4
  #define DSZ_PIN    PINA
5
  #define DSZ_DDR    DDRA
6
  #define DSZ_BIT    5
7
#elif  defined( __AVR_ATmega328__ )
8
  #define DSZ_VECT   PCINT0_vect
9
  #define DSZ_PORT   PORTB
10
  #define DSZ_PIN    PINB
11
  #define DSZ_DDR    DDRB
12
  #define DSZ_BIT    1
13
#ekse
14
  #error device Not supported (yet)
15
#endif
(die konkreten Werte sind mal so aus dem Höhlen Bauch)

Und als Tip (passend zum Nick):
Viel fremden Code anschauen. Die Anderen machen nicht alles falsch.

: Bearbeitet durch User
von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Carl D. schrieb:
> den AVR erkennt man nicht am Vorgandensein von PORTA,

der AVR interessiert nicht. Wenn es PORTA gibt, ist die Zuordnung

PORTA => PCINT0 etc.

sonst um eins versetzt:

PORTB => PCINT0 etc.

Es geht mir im Prinzip nur darum, die Auswahl
#define dsz_int_port     2
einzusparen und in Abhängigkeit von

#define dsz_port    D
zu bringen.

Scheint nicht so einfach zu sein.



lalala schrieb:
> sollte aber. Wie testest du, ob es funktioniert?

ich setze einen Fehler in die betreffende Auswahl und schaue, ob es eine 
Fehlermeldung gibt oder ob der Fehler übersprungen wird.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> das hatte ich probiert.
>
> #if dsz_port=='B'

Und wie hast Du dsz_port definiert? Da musst Du natürlich auch 
Hochkommata verwenden. Sonst wird das nichts.

D (ohne Hochkommata) ist für den Präprozessor undefiniert (es sei denn, 
Du hast ein #define D irgendwas irgendwo davor stehen).

'D' (mit Hochkommata) ist hingegen eine Konstante.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Du hast ein #define D irgendwas irgendwo davor stehen)

Nein. der Buchstabe D wird mittels GLUE mit der Buchstabenfolge 
PIN,PORT,DDR verbunden. PIN ist für sich nix - zusammen mit D findet es 
sich als Definition in io.h. mit 'D' würde GLUE nicht funktionieren. 
Wahrscheinlich ist das die Besonderheit von GLUE, dass nix mit nix 
verbunden wird und dann etwas ergibt. Nix ist dann aber für einen 
Macro-Vergleich ungeeignet.


1
#if dsz_int_port==0
2
#define dsz_vect   PCINT0_vect
3
#endif
4
#if dsz_int_port==1
5
#define dsz_vect   PCINT1_vect
6
#endif
7
#if dsz_int_port==2
8
#define dsz_vect   PCINT2_vect
9
#endif
10
#if dsz_int_port==3
11
#define dsz_vect   PCINT3_vect
12
#endif
13
14
#define PCMSK(x)    GLUE(PCMSK, x)
15
#define PCIE(x)      GLUE(PCIE, x)
16
17
18
19
20
//-----------------------------------
21
dsz_init()
22
{
23
DDR(dsz_port)&=~(1<< dsz_pin);
24
//PORT(dsz_port)|=((1<< dsz_pin));
25
PCICR |= (1 << PCIE(dsz_int_port));//PCIntControlRegister
26
PCMSK(dsz_int_port) |= (1<< dsz_pin);
27
sei();
28
}
29
30
//--------------------------------------------------
31
32
ISR(dsz_vect){
33
dsz_isr_imp++;
34
//if (PIN(dsz_port)&(1<<dsz_pin)) led1_on;else led1_off;
35
}
36
37
//--------------------------------------------------
38
39
isr_dsz_start(){
40
PCMSK(dsz_int_port) |= (1 << dsz_pin);
41
42
}
43
44
//--------------------------------------------------
45
46
isr_dsz_stop(){
47
PCMSK(dsz_int_port) &=~(1 << dsz_pin);
48
}

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> Nein. der Buchstabe D wird mittels GLUE mit der Buchstabenfolge
> PIN,PORT,DDR verbunden.

Nicht, wenn Du

#if bla===D

schreibst. Da ist kein "GLUE".

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> grundschüler schrieb:
>> Nein. der Buchstabe D wird mittels GLUE mit der Buchstabenfolge
>> PIN,PORT,DDR verbunden.
>
> Nicht, wenn Du
>
> #if bla==D
>
> schreibst. Da ist kein "GLUE".

Deswegen scheint es nicht so zu funktionieren, wie ich mir das gedacht 
hatte.

Das merkwürdige ist, dass es bei der Verbindung von Ziffern im Vergleich
#if bla==2 und mit GLUE funktioniert.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Ziffern sind Konstanten. Bezeichner (Dein "D") nicht.

von Johann L. (gjlayde) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
lalala schrieb:
> grundschüler schrieb:
>> das hatte ich probiert.
>>
>> #if dsz_port=='B'
>> #define dsz_vect   PCINT0_vect
>> #endif
>> #if dsz_port=='C'
>> #define dsz_vect   PCINT1_vect
>> #endif
>> #if dsz_port=='D'
>> #define dsz_vect   PCINT2_vect
>> #endif
>>
>> geht auch nicht.
>
> sollte aber.

Nein, sollte nicht.

Der Präprozessor kann nur numerische Werte vergleichen, keine Strings.

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
>
> Der Präprozessor kann nur numerische Werte vergleichen, keine Strings.

Und undefinierte Macros haben den numerischen Wert 0

von lalala (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Johann L. schrieb:
> lalala schrieb:
>> sollte aber.
>
> Nein, sollte nicht.
>
> Der Präprozessor kann nur numerische Werte vergleichen, keine Strings.

'B', 'C', 'D', etc. sind in C ja auch keine Strings. Ist das im 
Präprozessor anders?

Ich habe jetzt aber mal ein paar Codeschnipsel durch den GCC gejagt:
1
//#define TEST A //Option 1
2
#define TEST 'A' //Option 2
3
#if TEST=='A'
4
#warning TEST == 'A'
5
#else
6
#if TEST == A
7
#warning TEST == A
8
#else
9
#warning TEST ist was anderes
10
#endif
11
#endif

Mit Option 1: TEST == A
Mit Option 2: TEST == 'A'

Außerdem habe ich mal geraten, was der TO erreichen will und etwas in 
die Richtung gebaut:
1
#define GLUE(X, Y) X ## Y
2
//#define TEST2A B  //Option 1
3
#define TEST2A 'B'  //Option 2
4
#define TEST2(X) GLUE(PORT, X)
5
#if TEST2(A)=='B'
6
#warning TEST2A == 'B'
7
#else
8
#if TEST2(A) == B
9
#warning TEST2A == B
10
#else
11
#warning TEST2A ist was anderes
12
#endif
13
#endif

Bei beiden Optionen ist das Ergebnis: TEST2A==B
Das hatte ich ehrlich gesagt nicht so erwartet. Falls ich einen Fehler 
im Code habe, bitte melden :)

von Walter S. (avatar)


Bewertung
0 lesenswert
nicht lesenswert
lalala schrieb:
> Ich habe jetzt aber mal ein paar Codeschnipsel durch den GCC
> gejagt://#define TEST A //Option 1
> #define TEST 'A' //Option 2
> #if TEST=='A'
> #warning TEST == 'A'
> #else
> #if TEST == A
> #warning TEST == A
> #else
> #warning TEST ist was anderes
> #endif
> #endif
> Mit Option 1: TEST == A
> Mit Option 2: TEST == 'A'

wenn Du
#if TEST == Z
schreibst kommt übrigens genauso
TEST == A
raus

von PittyJ (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Der Thread bestärkt meine Meinung, dass Anfänger nicht mit Macros 
arbeiten sollten. Normaler C-Code würde das Problem auch lösen. Das 
sieht villeicht nicht so elegant aus, dafür ist es für jeden zu 
verstehen.

Anfänger: lasst einfach die Finger von #. Das einzige, was ihr braucht 
ist #include.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Das funktioniert nicht, wenn man Code schreiben möchte, den man für 
unterschiedliche AVRs übersetzen können möchte. Wenn der eine bestimmte 
Register nicht hat, kann der Code für diesen Controller gar nicht erst 
übersetzt werden; da ist bedingte (d.h. per #if / #ifdef gesteuerte) 
Compilation zwingend erforderlich.

Obendrein würde eine Fallunterscheidung zur Laufzeit viel überflüssigen 
Code erzeugen.

Der Präprozessor ist ein wichtiges Werkzeug; ihn verstehen und anwenden 
können gehört dazu.

Man muss allerdings auch nicht ums Verrecken alles mit dem Präprozessor 
erledigen.

Ist es wirklich nötig, Registernamen mit viel MagicFoo(tm) vom 
Präprozessor zusammenbasteln zu lassen, nur weil man tippfaul ist?

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> Ist es wirklich nötig, Registernamen mit viel MagicFoo(tm) vom
> Präprozessor zusammenbasteln zu lassen, nur weil man tippfaul ist?


Alles was der Präprozessor automatisiert erledigt, erzeugt keine Fehler. 
Wenn ich den Pin wechsele, brauche ich nur die Defines
#define dsz_port         D
#define dsz_pin          5
#define dsz_int_port     2

richtig zu machen. Der ganze PCINT-Code wird dann automatisch richtig 
angepasst.  Ohne Macros muss man den Code an vielen Stellen ändern. 
Dadurch ergeben sich Fehlermöglichkeiten.

Das ist nicht nur Tippfaulheit sondern auch Fehlervermeidung.

Ich könnte das noch reduzieren indem ich nur

#define dsz_pin          5
#define dsz_int_port     2

definiere oder die Durchnummerierung von Arduino verwende:

#if dsz_int_port ==   0
#define dsz_port   B
#endif
#if dsz_int_port ==   1
#define dsz_port   C
#endif
#if dsz_int_port ==   2
#define dsz_port   D
#endif

Allerdings möchte ich den D5-Pin auch so bezeichnen, weil das bei AVRs 
geläufig ist. Man weiß dann gleich welcher Pin gemeint ist.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
grundschüler schrieb:
> #define dsz_port         D

Genau da liegt halt das Problem.

Hätte D einen Wert, könntest Du es auch inhaltlich (d.h. mit 
Vergleichsoperationen) auswerten. Es hat aber keinen, es ist nur ein 
symbolischer Name, und damit kannst Du außer mit Deiner "glue logic" 
nichts weiter anfangen.

von grundschüler (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> nichts weiter anfangen.

ja doch:

#define pinSET(x,y)     PORT(x) |=(1<<y)
#define pinCLR(x,y)     PORT(x)&=~(1<<y)
#define pinTOG(x,y)     PORT(x)^=(1<<y)
#define pinVAL(x,y)     (PIN(x)&(1<<y))
#define pinDIRin(x,y)     DDR(x)&=~(1<<y)
#define pinDIRout(x,y)     DDR(x)|=(1<<y)
#define pinPULLUP(x,y,z) 
(z)?(PORT(x)|=(1<<y)):(PORT(x)&=~(1<<y))//0_no

wenn dsz_port einmal definiert ist, kann man da viel mit machen.

von Kaj (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Rufus Τ. F. schrieb:
> da ist bedingte (d.h. per #if / #ifdef gesteuerte)
> Compilation zwingend erforderlich.
>
> Obendrein würde eine Fallunterscheidung zur Laufzeit viel überflüssigen
> Code erzeugen.
Oder man macht es wie im "GNU Coding Standards, Chapter 3.5"
https://www.gnu.org/prep/standards/standards.html#Conditional-Compilation
1
3.5 Conditional Compilation
2
3
When supporting configuration options already known when building your
4
program we prefer using if (... ) over conditional compilation, as in
5
the former case the compiler is able to perform more extensive checking
6
of all possible code paths.
7
8
For example, please write
9
10
  if (HAS_FOO)
11
    ...
12
  else
13
    ...
14
15
instead of:
16
17
  #ifdef HAS_FOO
18
    ...
19
  #else
20
    ...
21
  #endif
22
23
A modern compiler such as GCC will generate exactly the same code in
24
both cases, and we have been using similar techniques with good success
25
in several projects. Of course, the former method assumes that HAS_FOO
26
is defined as either 0 or 1.
27
28
While this is not a silver bullet solving all portability problems, and
29
is not always appropriate, following this policy would have saved GCC
30
developers many hours, or even days, per year.

Hat mit dem konkreten Problem wenig zu tun, es sei aber trotzdem mal 
angemerkt im Zuge der "ohne geht es nicht"-Behauptung ;)

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht lesenswert
Alles benötigte kann die Sprache eines gewissen Bjarne auch ohne #.

von Rufus Τ. F. (rufus) (Moderator) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Kaj schrieb:
> es sei aber trotzdem mal angemerkt im Zuge der "ohne geht es
> nicht"-Behauptung

Das geht nur dann, wenn sämtliche symbolische Namen, die hier verwendet 
werden, immer bekannt sind.

Gerade das aber ist im AVR-Umfeld nicht gegeben; für unterschiedliche 
AVRs werden unterschiedliche Headerdateien eingebunden, die 
unterschiedliche Peripherieregister definieren.

Versucht man nun, Code zu schreiben, der beispielsweise eine zweite, nur 
bei einem bestimmten AVR-Typ vorhandene UART ansteuert, fliegt der 
Compiler auf die Schnauze, wenn das für einen anderen AVR-Typ übersetzt 
werden soll, weil die symbolischen Namen für die Register der zweiten 
UART undefiniert sind.

Da muss dann der die zweite UART ansteuernde Code mit bedingter 
Compilation, d.h. durch #if / #ifdef auskommentiert werden.

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]
  • [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.