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
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
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 ?
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.
@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).
> 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.
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
>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
> 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.
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
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?
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 :((((
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:
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 :)
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
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:
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.
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
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