Hallo zusammen,
ich suche nach einer Möglichkeit mittels Concat einen Makronamen
zusammenzusetzen und diesem dann einen Wert zuzuweisen. Also etwa wie
folgt:
1
#define CONCAT(X,Y) X##_##Y
2
#define TEMPLATE(X,Y) CONCAT(X,Y)
3
#define PREFIX test
4
5
// gewünscht wäre ein Makro namens test_SYMBOL mit dem Wert 8
6
#define TEMPLATE(PREFIX,SYMBOL) (8)
Die letzte Zeile wird mit folgender Warnung quittiert:
incompatible redefinition of macro "TEMPLATE"
Ist ja auch klar, aber was muss ich tun um das umzusetzen oder geht das
gar nicht?
Das geht nicht.
Dazu müsste der Präprozessor sich selbst eine Makrodefinition erzeugen,
in der dann der Name des Makros im Laufe des Prozesses entsteht. Das ist
aber ausserhalb der Möglichkeiten des Präprozessors.
Aber wenn es nicht unbedingt ein beliebiger neuer Makro sein muss,
der da rauskommt, kann man so einen Ansatz schon verfolgen. Typisches
Beispiel ist bei einem AVR, aus dem Portbuchstaben („B“) die drei
Namen für die Port-Register („PORTB“, „DDRB“ und „PINB“) zu zimmern.
Jörg Wunsch schrieb:> Typisches> Beispiel ist bei einem AVR, aus dem Portbuchstaben („B“) die drei> Namen für die Port-Register („PORTB“, „DDRB“ und „PINB“) zu zimmern.
Wie soll das gehen?
Bei einem Macro kann nur die rechte Seite Macros beinhalten, niemals die
linke Seite.
Jörg Wunsch schrieb:> Peter Dannegger schrieb:>>> Typisches>>> Beispiel ist bei einem AVR, aus dem Portbuchstaben („B“) die drei>>> Namen für die Port-Register („PORTB“, „DDRB“ und „PINB“) zu zimmern.>>>> Wie soll das gehen?>> Beitrag "Re: Linux und (immer noch) C"
Ist allerdings nicht ganz vergleichbar.
Was der TO in erster Linie machen will, das ist dass er hier
1
#define Makro Ersetzung
2
*****
den Namen des Makros per anderen Makros zusammenbauen lässt.
Was so erst mal nicht geht.
Also muss er einen Plan B ins Auge fassen. Der könnte so aussehen, wie
du das gezeigt hast, dass sich ein Makro aus einem anderen Makro den
Teil aus dem Ersetzungstext rausholt den es braucht.
Aber ein
1
#define PREFIX cfg
2
#define SYMBOL Offset
3
4
#define TEMPLATE(PREFIX,SYMBOL) (8)
welches dann dafür sorgt, dass damit eine gleichwertige Funktionalität
zu
1
#define cfg_Offset (8)
erreicht wird, ist so nicht möglich. Ein derartiges hypothetisches Makro
'TEMPLATE' ist mit dem Präprozessor nicht formulierbar.
Karl Heinz schrieb:> Ist allerdings nicht ganz vergleichbar.
Ja. Dass das, was er da als Wunschvorstellung formuliert hat, so
nicht machbar ist, ist schon klar. Aber vielleicht lässt sich ja
das, was er dann mit den neu definierte Makros anstellen will,
dennoch auf so einem Weg erreichen.
Ich würde mit dem Ergebnis gerne die Anzahl Elemente eines Arrays
festlegen, also:
1
uint8_ttest_array[test_SYMBOL];
Dieses Array ist Teil einer Struktur, die innerhalb einer header-Datei
deklariert ist um sie in anderen Modulen verwenden zu können.
Ich könnte auch mit
Eric B. schrieb:> Edit: wobei dann eigentlich für alle mögliche Zugriffe auf den FIFO> Makros definiert werden sollen z.B.
Das ist nicht das Problem - das funktioniert bereits alles. Der einzige
kleine Schönheitsfehler an der Sache ist momentan, dass alle FIFOs
dieselbe Anzahl an Elementen haben (müssen).
Micha schrieb:> Der einzige> kleine Schönheitsfehler an der Sache ist momentan, dass alle FIFOs> dieselbe Anzahl an Elementen haben (müssen).
Du kannst doch auch die Größe den Macros als Argument übergeben bzw. in
den Funktionen mit sizeof() ermitteln.
Nachtrag
Die Lösung wäre mir trotzdem zu frickelig.
Frage: warum brauchst du überhaupt die Größe als Konstante? Solange du
nicht über irgendwelche (void *) auf die Fifo zugreifts, kannst Du doch
über sizeof(entry)/sizeof(entry[0]) die Größe immer ermitteln.
Oder packe die Size einfach mit in die struct.
Braucht 2 Byte mehr, aber macht das ganze transparenter (Init der Size
nicht vergessen...)
Irgendwo hatt ich genau deinen Ansatz mit diesem Konstrukt…Mmmm
Peter Dannegger schrieb:> Du kannst doch auch die Größe den Macros als Argument übergeben bzw. in> den Funktionen mit sizeof() ermitteln.Micca schrieb:> Frage: warum brauchst du überhaupt die Größe als Konstante?
Um die Anzahl der Elemente zu definieren, sprich wie viel Platz das FIFO
bietet. Das heißt wie viele Arrays oder Strukturen passen in das FIFO?
Die Größe eines dieser Elemente bestimme ich tatsächlich mit sizeof.
Der Ansatz mit dem enum funktioniert:
Es gibt ja ein paar Leute hier im Forum, die C++ auf Microcontrollern
als Katastrophe ansehen. Würde mich interessieren, ob sie dieses Gewürge
hier für sinnvoller halten.
Naja eine Augenweide ist es nicht unbedingt, das stimmt schon. Aber ich
könnte mir durchaus auch Schlimmeres vorstellen...
Als jemand, der keinerlei C++ Erfahrung hat: wäre es denn möglich eine
entsprechende Klasse mit Templates zu erstellen und diese dann in einem
"normalen" C-Projekt zu verwenden?
Moin, ich programmiere embedded Systeme sowohl in C als auch in C++ ,
kurz meine 5 Cent…
> Als jemand, der keinerlei C++ Erfahrung hat: wäre es denn möglich> eine entsprechende Klasse mit Templates zu erstellen und diese> dann in einem "normalen" C-Projekt zu verwenden?
Ja, das ist möglich, aber warum? Es tut was es soll.
Du hast die Auswahl der Programmiersprache gemacht, weil Du dich damit
auskennst. Du hattest das Problem viele unterschiedliche FIFOs zu
benötigen und hast eine Lösung dafür gefunden. (BTW: wie viele sind es
denn tatsächlich…?)
Statt dann einen C++ Wrapper auf C zu bauen hätte ich es gleich komplett
in C++ erstellt (unabhängig davon ob Klassen genutzt werden oder nicht).
Ich empfehle gerne die C++ FAQ: „Is C++ better than…?“
http://isocpp.org/wiki/faq/big-picture#imperfect-language
Bzw „Is it important to know the technical definition of “good OO”? Of
“good class design”? ¶ ?
http://isocpp.org/wiki/faq/big-picture#biz-dominates-tech
Ich kann mit der Lösung leben, würde sie aber nicht in einem großen
kommerziellen Projekt nutzen, wenn die restlichen Programmierer dieses
Konstrukt nicht kennen und anwenden müssten. Da wären mir die Risiken
für Fehler zu groß (und Fehlersuche kostet Zeit, also Geld).
Ein Nachteil in meinen Augen ist Includierung von C Dateien in C
Dateien. Auch die lose Kopplung zw. Array und enum (test_FIFO,
test_FIFO_SIZE) gefällt mir nicht. Aber was soll’s, es funktioniert.
Hallo Micha
(BTW: hoffe dass die Namensgleichheit nicht alle Mitleser verwirrt).
Eine Frage ist mir noch eingefallen:
C-Makros kann man meist nicht gut debuggen. Die Toolchains können damit
nicht umgehen.
Wie ist das in Deinen Template() Funktionen? Kann man hineinspringen
(Step-Into) und in Einzelschritten (Single Step) durchsteppen?
Breakpunkt setzen geht vermutlich nicht. Korrekt?
Micha schrieb:> Als jemand, der keinerlei C++ Erfahrung hat: wäre es denn möglich eine> entsprechende Klasse mit Templates zu erstellen und diese dann in einem> "normalen" C-Projekt zu verwenden?
99% des normalen C-Codes lässt sich ohne Änderungen mit einem
C++-Compiler übersetzen. Die restlichen 1% (fehlende Casts bei void*
etc.) sind schnell korrigiert. Ausnahme sind ggf.
compiler/plattformpezifische Konstrukte.
Sofern es für Deine Plattform einen C++-Compiler gibt, könntest Du das
Projekt also recht einfach auf den C++-Compiler umstellen. Ab dann
kannst Du im bestehdenen Code Templates, Klassen usw. verwenden.
Wie viel C++-Features Du benutzt, liegt ganz an Dir. Man kann auch mit
C++ reines C programmieren.
Micca schrieb:> BTW: wie viele sind es denn tatsächlich…?
Ehrlich gesagt hätte ich die FIFOs locker noch von Hand pflegen können,
sprich die Dateien kopieren und die Namen umbenennen. Aber mir gefiel
nicht, dass ich etwaige Änderungen dann in allen Kopien machen und bei
jeder neuen Verwendung alle Namen ändern muss. Und generische Namen
fördern die Übersicht imo nicht unbedingt. Ich sehe es daher als eine
Art Machbarkeitsstudie.
Micca schrieb:> Auch die lose Kopplung zw. Array und enum (test_FIFO,> test_FIFO_SIZE) gefällt mir nicht.
Das ist aber mehr oder weniger ein generelles Problem mit enums in C,
nicht?
Micca schrieb:> Wie ist das in Deinen Template() Funktionen? Kann man hineinspringen> (Step-Into) und in Einzelschritten (Single Step) durchsteppen?
Ja, das geht. Unschön dabei ist jedoch, dass nicht der tatsächliche
aktuelle Name angezeigt wird, sondern der zuerst definierte. Man muss
also wissen in welcher Funktion man sich befindet.
Da ich aber bspw. "test1_FifoRead()" aufrufe, kann ich damit leben. D.h.
in meinem Code nutze ich nicht mehr die Templates, sondern die Namen,
die der Compiler daraus gemacht hat.
IDE ist CodeComposerStudio 5.5 bzw. Eclipse Luna für STM32 aufbereitet.
Micca schrieb:> Breakpunkt setzen geht vermutlich nicht. Korrekt?
Das geht bedingt. Je nach Position des BP müssen alle anderen erstmal
deaktiviert werden. Und es sieht so aus als würde ein BP in jeder der
generierten Funktionen gesetzt, da das Debugging immer dort stoppt, egal
ob "test1_FifoRead()" oder "test2_FifoRead()" aufgerufen wurde. Die
Sache mit den Namen von oben gilt natürlich ebenfalls.
Wie steht es hinsichtlich dieser beiden Punkte bei Benutzung von C++
Templates? Kann ein Breakpoint dort speziell in einer einzelnen
Implementierung (oder wie auch immer das dann heißt) gesetzt werden?
Sagen wir mal bei Benutzung o.g. IDE und dem GCC.
Hans schrieb:> Wie viel C++-Features Du benutzt, liegt ganz an Dir. Man kann auch mit> C++ reines C programmieren.
Zukünftig werde ich definitiv darüber nachdenken. Ich denke auch der
Overhead ist zu verschmerzen und hält sich in Grenzen wenn man auf ein
paar Dinge achtet.