Forum: Compiler & IDEs Präprozessor Problem


von TheMason (Gast)


Lesenswert?

Hallo leute,

ich habe folgendes konstrukt :

c-datei :

  #define OS_FIFO_SECTION

  #define OS_FIFO(name,size,signal) UCHAR aucFIFOData_##name## [size];
    #include "config/os_fifo.cfg"
  #undef OS_FIFO

os_fifo.cfg :


  #ifdef OS_FIFO_SECTION
  //OS_FIFO (name,                 size,        signal      )
    OS_FIFO (OS_APP_EVENT_FIFO ,    20,    OS_APP_EVENT     )

  #endif


pfade sind soweit ich weiß richtig eingestellt (alles andere lässt sich 
compilieren)

die fehlermeldung des compilers :

pasting "aucFIFOData_OS_APP_EVENT_FIFO" and "[" does not give a valid 
preprocessing token

dasselbe habe ich mit einem per define definierten unsigned char array.
der witz ist das es an anderen stellen im code klappt.
müssen noch irgendwelche optionen beim gcc aktiviert werden damit der 
das frißt ?!

gruß
rene

von pumpkin (Gast)


Lesenswert?

Mal so versucht?:
1
#define OS_FIFO((name),(size),signal) UCHAR aucFIFOData_##(name)##[(size)];

Sind die Rauten dort erlaubt? Frage an die Experten.

pumpkin

von TheMason (Gast)


Lesenswert?

die ## sind erlaubt und bedeuten einfach nur eine verkettung der 
gegebenen parameter z.b. wird aus :

#define test(x,y) parameter_##x##_##y##

bei  test (nr, 1) -> parameter_nr_1

es scheint aber so zu sein das der gcc es nicht mag wenn man per define 
ein komplettes array definiert (obwohl es doch auch nur reine 
textersetzung ist).
muß man da im gcc was einstellen ? (kommt mir fast so vor)

gruß
rene

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das Semikolon am Ende der #define-Zeile (also hinter ]) würde ich 
weglassen.

von TheMason (Gast)


Lesenswert?

funzt auch nicht. hätte mich aber auch gewundert, denn das braucht der 
gcc ja um das ende der deklaration zu erkennen. außerdem meckert der ja 
schon das [ an ... :-((
ist der identifier vielleicht zu lang ?

von yalu (Gast)


Lesenswert?

Das zweite ## (vor dem [) ist zuviel. ## verknüpft zwei einzelne Tokens 
zu einem. [ ist aber immer ein einzelnes Token und braucht (und darf) 
deswegen nicht mit etwas anderem verknüft zu werden.

von TheMason (Gast)


Lesenswert?

@yalu

jau danke ... das hilft ...
aber warum meckert der dann an anderen stellen nicht (verwende diese 
konstuktion(en) ca. 50-60 mal in meinem quellcode).

von yalu (Gast)


Lesenswert?

> aber warum meckert der dann an anderen stellen nicht

Gleiche Makrodefinition? Gleicher Aufruf? Wenn nicht, zeig mal ein
Beispiel für so einen Fall, wo es funktioniert.

von TheMason (Gast)


Lesenswert?

beispiel :

c-file :

    #define BD_STATUS_LED_SEQ(name,data) const UCHAR auc##name## [] = 
data;
       #include "..\config/bd_statusled.cfg"
    #undef  BD_STATUS_LED_SEQ


    const UCHAR *apucStatusLedSeqs [] = {
      #define BD_STATUS_LED_SEQ(name,data) ((UCHAR *) &(auc##name##)),
         #include "..\config/bd_statusled.cfg"
      #undef  BD_STATUS_LED_SEQ
    };

    const UCHAR aucStatusLedSeqsLens [] = {
      #define BD_STATUS_LED_SEQ(name,data) (sizeof (auc##name##) - 1),
         #include "..\config/bd_statusled.cfg"
      #undef  BD_STATUS_LED_SEQ
    };

cfg-file :

    #ifdef BD_STATUS_LED_SEQ
      BD_STATUS_LED_SEQ (SL_SEQ_IDLE      , 
"\x01\x02\x03\x04\x05\x06\x07\x08\x07\x06\x05\x04\x03\x02\x01\x00\x0f")
      BD_STATUS_LED_SEQ (SL_SEQ_BLINKFAST     , "\x00\x0f")


    #endif


in diesem (teil)-projekt verwende ich auch die konstrukte von oben 
(OS_FIFO), da meckert der zwar auch, aber erzeugt keinen error, sondern 
nur ne warnung.
merkwürdig ... aber vielleicht klappt es ja mit nur einem ##


aber direkt noch mal ein paar fragen zum präprozessor :

ich möchte den namen der include-files (für meine confgi-files) per 
define festlegen, also so :

#define FILE_NAME "xyz.cfg" // ist in der header datei definiert

...

#define blabla       // wird in der header und in der c datei verwendet
  #include FILE_NAME
#undef blabla

so. funktioniert auch, allerdings nur in header-dateien. in den 
c-dateien sagt der gcc das der FILE_NAME nicht mehr kennt (jedenfalls 
ist die fehlermeldung "#include expects "FILENAME" or <FILENAME>".
kann es sein das der das define irgendwie verbummelt ?!

gruß
rene

von Oliver (Gast)


Lesenswert?

>kann es sein das der das define irgendwie verbummelt ?!

Nö. In geschätzten 100,0000% aller Fälle hat der Programmierer das 
define verbummelt.
Eigentlich ist es völlig egal, ob da was in einer .h oder .c-Datei 
steht. Nur die Reihenfolge muß stimmen. Wenn er anmeckert, daß er 
FILENAME nicht kennt, dann kennt er das halt nicht. Ergo ist es vorher 
nicht definiert.

Oliver

von yalu (Gast)


Lesenswert?

> in diesem (teil)-projekt verwende ich auch die konstrukte von oben
> (OS_FIFO), da meckert der zwar auch, aber erzeugt keinen error,
> sondern nur ne warnung.

Also mein GCC (4.0.1, ok nicht der neueste) bzw. der Präprozessor
liefert, wie ich es erwartet hätte, 6 Errors, in denen er erzählt,
dass er keinen Identifier mit einer Klammer verkleben kann (Dateinamen
und Zeilennummer habe(n) (s)ich geändert):

  In file included from prep2.c:2:
  prep2.cfg:3:1: error: pasting "aucSL_SEQ_IDLE" and "[" does not give
  a valid preprocessing token
  prep2.cfg:4:1: error: pasting "aucSL_SEQ_BLINKFAST" and "[" does not
  give a valid preprocessing token

  In file included from prep2.c:7:
  prep2.cfg:3:1: error: pasting "aucSL_SEQ_IDLE" and ")" does not give
  a valid preprocessing token
  prep2.cfg:4:1: error: pasting "aucSL_SEQ_BLINKFAST" and ")" does not
  give a valid preprocessing token

  In file included from prep2.c:13:
  prep2.cfg:3:1: error: pasting "aucSL_SEQ_IDLE" and ")" does not give
  a valid preprocessing token
  prep2.cfg:4:1: error: pasting "aucSL_SEQ_BLINKFAST" and ")" does not
  give a valid preprocessing token

Ohne das zweite ## gibt es keinen Fehler.

Der Standard sagt:

  "If the result [of a ## concatenation] is not a valid preprocessing
  token, the behavior is undefined."

Und aucSL_SEQ_IDLE[ ist nun mal kein valides Token, sondern zwei. Und
weil das Verhalten undefiniert ist, kann es sein, dass dein Compiler
anders reagiert als meiner.

>> kann es sein das der das define irgendwie verbummelt ?!
>
> Nö. In geschätzten 100,0000% aller Fälle hat der Programmierer das
> define verbummelt.

Ich würde mich da Olivers Meinung anschließen ;-)

Bei mir geht's auf jeden Fall. Entweder

- fehlt das #define FILE_NAME in der Headerdatei aus irgend einem
  Grund doch,

- wird das FILE_NAME an anderer Stelle ge#undeft oder

- du includest das Headerfile nicht vor der Verwendung von
  FILE_NAME.

von TheMason (Gast)


Lesenswert?

erst mal danke für die tips.
werds mir mal angewöhnen mit einem ## zu arbeiten.
den fehler mit dem include-filename-define muß ich noch mal schauen 
wodran das liegt.
dazu vielleicht nochmal eine kleine frage :

ich möchte es gerne so machen das ich pfad und dateinamen über zwei 
separate defines definiere und nachher zu einem filenamen 
zusammendrösel, so z.b. :

#define BD_DEVICE_CONFIG_PATH "config/"
#define BD_DEVICE_PARSER "parser.cfg"

#define BD_DEVICE_CONFIG_FILE BD_DEVICE_CONFIG_PATH##BD_DEVICE_PARSER

#include BD_DEVICE_CONFIG_FILE

nur das das include dann ein problem kriegt weil laut textersetzung ja 
das herauskommt :

#include "config/" "parser.cfg" und nicht

#include "config/parser.cfg"

gibt es da ne möglichkeit ?

dank und gruß
rene

von yalu (Gast)


Lesenswert?

Auweia, jetzt wird's schwierig =:-|

Wir haben hier mit dem Problem zu kämpfen, dass der C-Präprozessor,
der (eigentliche) C-Compiler und das Dateisystem des Betriebssystems
gewisse Zeichenfolgen ganz unterschiedlich interpretieren :(
1
#define A "foo"
2
#define B "bar"
3
#define C A B
funktioniert problemlos, wenn C als Stringkonstante verwendet wird, da
- als String betrachtet - "foo" "bar" vom Compiler zu "foobar"
zusammengefügt werden.

Aber das, was hinter dem #include steht, sieht zwar aus wie ein
String, ist aber keiner. Der Präprozessor, der das #include
verarbeitet, fügt die beiden Teil"strings" leider nicht zusammen :((

Man muss sich also irgendwie der überschüssigen Anführungszeichen
entledigen, was aber m. W. nicht möglich ist :(((

Also erst einmal gar nicht so viele Anführungszeichen hinschreiben, z.
B. so:
1
#define BD_DEVICE_CONFIG_PATH config/
2
#define BD_DEVICE_PARSER parser.cfg
Aber wie bekommt man nun die beiden Bestandteile lückenlos aneinander?
1
#define BD_DEVICECONFIG_FILE BD_DEVICE_CONFIG_PATH BD_DEVICE_PARSER
hinterlässt ein hässliches Leerzeichen in der Mitte. In einem
C-Programm stören Leerzeichen zwischen dem /-Operator und einem
nachfolgenden Variablennamen nicht. Das Dateisystem interpretiert das
Leerzeichen allerdings als ersten Zeichen des Dateinamens :((((
1
#define BD_DEVICECONFIG_FILE BD_DEVICE_CONFIG_PATH ## BD_DEVICE_PARSER
geht ebenfalls nicht, da BD_DEVICE_CONFIG_PATH mit einem / endet, das
mit nichts anderem konkateniert werden kann :(((((

Also muss man dafür sorgen, dass BD_DEVICE_CONFIG_PATH nicht mit einem
/ endet, sondern mit einem Zeichen, das mit dem ersten Zeichen von
BD_DEVICE_PARSER zu einem Token (bspw. einem Identifier) konkateniert
werden kann. Ein Identifier beginnt mit einem Buchstaben oder einem _.
Hängt man also bspw. ein _ an das / an, bedeutet dies aus Sicht des
Dateisystems, dass das _ das erste Zeichen des Dateinamens ist. Wenn
du mit dieser Namensverunstaltung leben kannst, bietet sich folgende
Lösung deines Problems an:
1
// Hilfsmakros
2
#define CAT(x,y) x##y
3
#define STR2(x) #x
4
#define STR(x) STR2(x)
5
#define STRCAT(x,y) STR(CAT(x,y))
6
7
// Definition des Headerfiles
8
#define BD_DEVICE_CONFIG_PATH config/_
9
#define BD_DEVICE_PARSER parser.cfg
10
11
// Entweder so ...
12
#define BD_DEVICE_CONFIG_FILE STRCAT(BD_DEVICE_CONFIG_PATH, BD_DEVICE_PARSER)
13
#include BD_DEVICE_CONFIG_FILE
14
15
// ... oder alles in einer Zeile
16
#include STRCAT(BD_DEVICE_CONFIG_PATH, BD_DEVICE_PARSER)
Auf diese Weise wird die Datei

  config/_parser.cfg

includet.

Diese Lösung ist sicher nicht ganz befriedigend, aber das Beste, was
mir auf die Schnelle eingefallen ist.

Die vielen Hilfsmakros dienen übrigens nicht der Übersicht (die ist
sowieso nicht mehr gegeben), sonder tragen durch die damit erzwungene
mehrstufige Expnasion der etwas eigenartigen Expansionsreihenfolge des
Präprozessors Rechnung.

Das war also die Pfuschlösung ;)

Nun die Alternativen:

- Du betrachtest dein Gesamtproblem aus etwa 10 Meter Entfernung,
  vielleicht siehst du dann eine Lösung, die ganz ohne diese
  Präprozessorfrickeleien auskommt.

- Du hoffst, dass mindestens einer unserer Uber-1337-C-h4x0rz (dieser
  Ausdruck ist als Kompliment gemeint :) ) Karl Heinz Buchegger oder
  Jörg Wunsch zufälligerweise hier vorbeimarschiert. Wenn es überhaupt
  einen verborgenen C-Trick gibt, der das Problem in der von dir
  angedachten Weise löst, kennen die den, garantiert :)

von Karl H. (kbuchegg)


Lesenswert?

yalu wrote:
> - Du hoffst, dass mindestens einer unserer Uber-1337-C-h4x0rz (dieser
>   Ausdruck ist als Kompliment gemeint :) ) Karl Heinz Buchegger

Sorry.
Ich probier auch schon eine Weile herum, komm aber auch auf
keine Lösung. Ich bin noch nicht mal auf den Trick mit
dem Underscore gekommen.

Das Interessanteste, das ich zustande gebracht habe, ist Folgendes
1
#define BD_DEVICE_CONFIG_PATH \config\
2
#define BD_DEVICE_PARSER parser.cfg
3
4
#define STR(x) #x
5
#define STRINGIZE(X) STR(X)
6
#define B(X,Y) STRINGIZE(X##Y)
7
#define A(X,Y) B(X,Y)
8
#define BD_DEVICE_CONFIG_FILE  A(BD_DEVICE_CONFIG_PATH, BD_DEVICE_PARSER)
9
10
11
#include BD_DEVICE_CONFIG_FILE

mit der Fehlermeldung
1
../Forum9.c:11:31: error: \config#define BD_DEVICE_PARSER parser.cfgBD_DEVICE_PARSER: No such file or directory
Man beachte den Filenamen, der hier entsteht. Wo das #define
da mittendrin herkommt, kann ich absolut nicht erklären. Ich
denke da müsste man im Debugger den Präprozessor durchsteppen
um das zu verstehen.

Der Umweg über die A und B Mekros war eigentlich gedacht um
dem Präprozessor eine Auswertereihenfolge aufzuzwingen.

Mach ich das nicht:
1
#define STR(x) #x
2
#define STRINGIZE(X) STR(X)
3
#define B(X,Y) STRINGIZE(X##Y)
4
#define BD_DEVICE_CONFIG_FILE  B(BD_DEVICE_CONFIG_PATH, BD_DEVICE_PARSER)

dann lautet die Fehlermeldung
1
../Forum9.c:11:31: error: BD_DEVICE_CONFIG_PATHBD_DEVICE_PARSER: No such file or directory
was ja eigentlich schon sehr vielversprechend ist. Man muss
jetzt nur noch den Präprozessor dazu zwingen BD_DEVICE_CONFIG_PATH
bzw. BD_DEVIDE_PARSER zu ersetzen, bevor der Tokenpasting und Stringize
Mechanism,us greift. Daher der Zwischenschritt über ein Hilfsmakro.
Aber irgendwie versteht der Präprozessor diese Absicht nicht :-)
Mein Rat:
Löse das ganze über die Angabe von zusätzlichen Include
Pfaden beim Compileraufruf.

von Karl H. (kbuchegg)


Lesenswert?

AH.
Da haben mir die \ noch einen Streich gespielt.

von Oliver (Gast)


Lesenswert?

Solltest du einen Weg finden, der das Problem löst, dann beschwer dich 
aber bitte nicht hinterher, daß dein Programm nicht funktioniert, und du 
wüsstest nicht warum. Hoffentlich kannst du dann noch nachvollziehen, 
was der Compiler da alles zusammengebaut hat.

Gibt es wirklich keine Möglichkeit, für jede denkbare Konfiguration die 
anscheinend gleichnahmigen headerfiles in je ein eigenes 
Unterverzeichnisse zu packen, und das passende dann im makefile als 
Includepfad anzugeben?

Oliver

von TheMason (Gast)


Lesenswert?

also erstmal danke für die vielen infos. ich hatte schon befürchtet das 
das mit dem zusammenbauen von dateinamen per define nicht wirklich 
funktioniert (habe es vor knapp einem halben jahr mit dem iar mal 
probiert, aber pustekuchen).
ich werde es dann wohl so machen das ich in jeder headerdatei des 
entsprechenden moduls einen relativen pfad per define definiere (ist 
auch schonmal was, bisher habe bei jedem #include den dateinamen 
ausgeschrieben [also "config/bd_parser.cfg" statt 
BD_PARSER_CONFIG_FILE], und mich immer geärgert das ich bis zu 10 mal 
das include pro modul ändern muß wenn ich an der projekt-datei struktur 
was geändert habe).
hintergrund ist der das ich die o.g. module (z.b. einen parser, ein 
grafikdisplay mit mehreren fonts, mein os und und und) gerne 
konfigurieren möchte. (ist echt eine geile technik, und funktioniert 
wunderprächtig bis affenstark, und bietet ernormes 
erweiterungspotenzial).
dadurch kann die funktionalität der module durch die konfiguration 
wachsen.
vielleicht stelle ich das eine oder andere projekt mit dieser technik 
mal vor. ich denke das es für fortgeschrittene bestimmt interessant 
wäre.

dank und gruß
rene

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.