ich würde gerne Strukturen Namen mittels defines erstellen. Klappt so
nicht, geht das überhaupt? Kommt immer structXType_APPENDIX raus oder es
lässt sich nicht kompilieren.
GCC
Mike schrieb:> #define APPENDIX "xyz"> typedef struct{> short var;> }structXType_(APPENDIX);
Das würde "}structXType_("xyz");" ergeben.
Wenn überhaupt dann eher so:
1
#define APPENDIX structXType_xyz
2
...}APPENDIX;
Am ende ist das ganze ein simples suchen und ersetzen von Text.
Zusammenfügen von Variabelnname geht nur innerhalb des Macros:
Irgend W. schrieb:> #define OwnStruct(a) \> struct{ \> short var; \> }structXType_##a;> OwnStruct(xyz);
Danke das klappt aber hab da wohl etwas zu stark verkürzt hätte nämlich
in der struktur nochmal ein define das geht dann nicht
1
#define OwnStruct(a) \
2
struct{ \
3
#ifdef t1 \
4
short x; \
5
#endif \
6
}structXType_##a;
7
OwnStruct(xyz);
error: '#' is not followed by a macro parameter
Und nachdem ich da ganze viele verschiedene ifdef Varianten nochmal hab
kann ich das auch nicht rausnehmen..
An sich sollte die Struktur wo definiert sein und mit config files kann
man verschiedene typen der Struktur vor dem kompilieren anlegen.
Präprozessordirektiven wie #ifdef, #endif usw. sind innerhalb einer
makrodefinition nicht erlaubt.
Vielleicht solltest du mal etwas weiter ausholen und dein Problem als
Ganzes beschreiben.
Mike schrieb:> An sich sollte die Struktur wo definiert sein und mit config files kann> man verschiedene typen der Struktur vor dem kompilieren anlegen.
1
#ifdef t1
2
#define SHORT_X short x;
3
#else
4
#define SHORT_X
5
#endif
6
7
...
8
SHORT_X
führt aber ins Chaos. Keine Sau kann das lesen.
Für sowas nehme ich Textfresser (z.B. awk) und mache aus einer config
datei entsprechenden C-Code (.h/.c).
Vorteil: Du hast am Ende plain C-Code, für Dich, Deinen Debugger, Deine
IDE, ...
Mike schrieb:> ich würde gerne Strukturen Namen mittels defines erstellen. Klappt so> nicht, geht das überhaupt?
Das geht bestimmt, aber man tut das nicht. Der gcc versucht nur, dich
schonend auf den rechten Weg zu führen.
Bauform B. schrieb:> Das geht bestimmt, aber man tut das nicht. Der gcc versucht nur, dich> schonend auf den rechten Weg zu führen.
Das tut man schon und das ist manchmal auch ein richtiger Weg.
*Beispiel in c++*
Das Makro erstellt eine Register-Klasse für den Zugriff auf auf die
Hardware -Register z.B. für die Timer von ATtiny-261-461-861 wie im
Anhang beschrieben.
Was den Kommentar
Bauform B. schrieb:> Das geht bestimmt, aber man tut das nicht. Der gcc versucht nur, dich> schonend auf den rechten Weg zu führen.
äußerst eindrücklich unterstreicht.
Oliver
Mitleserin (a.b.) schrieb:> Das tut man schon
Aber sehr selten.
> und das ist manchmal auch ein richtiger Weg.
Noch seltener.
Ich würde für dein Beispiel einen kleinen Codegenerator mit z.B. Python
schreiben. Der könnte dann z.B. auch gleich noch automatisch die
XML-Beschreibungen der I/O-Register einlesen und verarbeiten.
Hallo,
was soll das denn überhaupt werden? Mir ist das noch zu kurz
beschrieben. Generell sollte man defines meiden wenn immer es möglich
ist. Warum soll ein struct überhaupt define abhängig sein?
Vor allem, warum will man
a) Ein C++-Template durch ein #define-Makro nachbauen
b) überhaupt die Registerzugriffe über Funktionen machen
c) die für alle möglichen Typen per einfachem cast. Wer braucht z.B.
Veit D. schrieb:> Generell sollte man defines meiden wenn immer es möglich ist.
Das ist nicht ganz richtig. Solange es lesbar (und das heisst auch: per
Textsuche auffindbar) ist, spricht nichts dagegen. Als Konfiguration (in
C) sind defines ein relativ gut standardisiertes und nutzbares Format.
Vor allem, weil man daraus ganz gute C-Fresser (in analogie zu
Textfressern) bauen kann.
Was nur unbedingt vermieden werden sollte, ist das erstellen oder nutzen
von Token, die nicht im Klartext vorliegen. Also genau das, was der TO
machen will.
Also ein MAX_CURRENT, WITH_ABC oder #define draw() drawLcd1455() sind
ok.
Ein "int abc(def);", dass zum "int abc_def;" wird (oder noch
abgefahrener), nicht. Zumindest wenn dessen Scope mehr als ein paar
Zeilen umfasst.
Mike schrieb:> ok dann bau ich einen Generator.
Eben, da du deine varianten auch steuern musst, wird sowas am besten im
Make mit integriert. und CMake könnte die Dateien erzeugen ....
Kochstudio schrieb:> Eben, da du deine varianten auch steuern musst, wird sowas am besten im> Make mit integriert. und CMake könnte die Dateien erzeugen .
Nun leg doch nicht sofort noch Mühlsteine oben drauf:
Zuerst den Generator. In der für ihn einfachsten Sprache.
Und den immer besser.
Und dann, falls mehr als einmal im Monat gebraucht, in cmake, wenn er
cmake verwendet.
Oder sein make. Oder seine Batchdatei. Aber das ist Kür. Guten C
sourcecode zu erstellen.isthier Pflicht
Mike schrieb:> ok dann bau ich einen Generator. Danke für die Meinungen.
Da kann ich auch noch eine Meinung beisteuern: Wenns mit Makros nicht zu
kompliziert ist (es wurde ja schon festgestellt, dass du nur zu viele
Anführungszeichen hattest), dann nimm Makros statt eines Generators.
Den Generator musst du nämlich auch pflegen. Und wenn sich der
generierte Code häufig ändert (sonst könntest du es ja gleich von Hand
schreiben), ins build-system (make oder cmake?) einbinden. Und dieses
build-System dann auch noch pflegen.
Und für den Generator musst du noch einen Compiler oder Interpreter mit
pflegen (den du, falls aller andere Code cross-compiliert ist, nicht
selbstverständlich hast).
Sebastian schrieb:> dann nimm Makros statt eines Generators
Das Problem ist, dass die Objekte nicht lesbar sind. Du hast ein
sObjektABC und keine Möglichkeit, die Definition oder Deklaration zu
finden.
Und nicht nur Du: auch der Debugger, die IDE, ... .
Prinzipiell sind die Infos im Klartext da, wenn man das ganze durch den
präprozessor jagt, nur fehlt dann z.b. jeder Kommentar.
Sebastian schrieb:> Mike schrieb:>> ok dann bau ich einen Generator. Danke für die Meinungen.>> Da kann ich auch noch eine Meinung beisteuern: Wenns mit Makros nicht zu> kompliziert ist (es wurde ja schon festgestellt, dass du nur zu viele> Anführungszeichen hattest), dann nimm Makros statt eines Generators.
Meine Aussage wäre inhaltlich zwar ähnlich (einfach->Makro,
kompliziert->Generator), aber ich würd's gerade umgekehrt sagen: Wenn es
mit Makros nicht sehr einfach ist, bau dir stattdessen einen Generator.
Vor allem ist hier, wie schon von anderen angemerkt, das Problem, dass
Identifier per Makro zusammengebaut werden.
> Den Generator musst du nämlich auch pflegen. Und wenn sich der> generierte Code häufig ändert (sonst könntest du es ja gleich von Hand> schreiben), ins build-system (make oder cmake?) einbinden.> Und dieses build-System dann auch noch pflegen.
Das ist in der Regel aber nicht besonders schwer. Muss man halt einmal
rausfinden, wie das geht, und danach kann man das immer wieder
verwenden.
> Und für den Generator musst du noch einen Compiler oder Interpreter mit> pflegen (den du, falls aller andere Code cross-compiliert ist, nicht> selbstverständlich hast).
Ich finde, wer ernsthaft programmiert, sollte sowieso zumindest eine
Skriptsprache einigermaßen können und dann natürlich auch den
Interpreter dafür bereits installiert haben. Im Falle von Python und
Linux (das ist in meinem Fall die Wahl) ist das sowieso schon
vorinstalliert.
Mit so einer Skriptsprache kann man einerseits solche Generatoren,
andererseits auch mal ein kleines "wegwerf-Skript" basteln, um schnell
irgendwas auszuprobieren oder etwas zu erzeugen, das man gerade braucht.
Ich mache das zumindest öfters.
A. S. schrieb:> Veit D. schrieb:>> Generell sollte man defines meiden wenn immer es möglich ist.> Das ist nicht ganz richtig. Solange es lesbar (und das heisst auch: per> Textsuche auffindbar) ...
Hallo,
es ist nicht die Frage ob richtig oder falsch. Die Frage lautet was ist
besser oder weniger besser. Was ist sicherer oder weniger sicherer.
Ich bin da eben anderer Meinung. defines kann man doppelt und dreifach
definieren. Das Letzte define gewinnt. Ich habe das schon vertreut im
Code gesehen wo sich jemand wunderte das es nicht richtig tut.
Maximal kommt eine redefine Warnung (kein Fehler), falls nicht
unterdrückt.
Ich weiß das C Programmierer ihre defines lieben und man kann damit
sicherlich sehr viel machen. Aber man kann damit auch sehr viel Mist
machen. Bspw. bei falscher Klammersetzung.
Veit D. schrieb:> Maximal kommt eine redefine Warnung (kein Fehler), falls nicht> unterdrückt.
Wer Warnungen unterdrückt oder ignoriert, hat die daraus entstehenden
Probleme verdient.
Veit D. schrieb:> Ich bin da eben anderer Meinung.
Eine andere Meinung ist ja OK. Doch sind rationale Argumente einfacher
zu diskutieren.
> defines kann man doppelt und dreifach definieren. Das Letzte define gewinnt. Ich
habe das schon [...] gesehen
Das ist m.E. kein Argument. Einen etablierten Mechanismus nicht zu
nutzen, weil andere damit Unsinn machen, hieße auf C in Gänze zu
verzichten.
Wenn Du hingegen ein Beispiel hast, dass mit Methode XY besser geht als
mit #define: Nur zu. Die fehlenden Identifier z.B. sind ein Argument.
Hallo,
die alles oder nichts Argumentation gefällt mir nicht. Wenn man defines
in C reduziert wo es möglich ist, wäre schon viel gewonnen. Zum Bsp.
Konstanten als Konstanten zu schreiben und nicht mit define. Eine define
"Formel" kann man auch als Funktion schreiben. Das alles heißt noch
lange nicht das man auf sein C verzichten muss.
Veit D. schrieb:> Zum Bsp. Konstanten als Konstanten zu schreiben und nicht mit define.
Wie genau macht man das? Willst du in jede C-Datei wo Pi gebraucht wird
ein
1
staticconstdoublepi=3.1413331233;
schreiben?
> Eine define "Formel" kann man auch als Funktion schreiben.
Auch hier ist die Frage, wie du erreichen willst, dass die Funktion die
gleichen (guten) Eigenschaften hat wie das Makro?
Veit D. schrieb:> die alles oder nichts Argumentation gefällt mir nicht. Wenn man defines> in C reduziert wo es möglich ist, wäre schon viel gewonnen. Zum Bsp.> Konstanten als Konstanten zu schreiben und nicht mit define.
Es gibt in C keine Konstanten außer die, die direkt als Wert
hingeschrieben werden. Deshalb nimmt man dafür ja define. Ich sehe auch
kein Problem darin, dafür #define zu benutzen.
> Eine define "Formel" kann man auch als Funktion schreiben.
Oft ja, und mit inlining bekommt man genau so optimierten Code.
mh schrieb:> Veit D. schrieb:>> Zum Bsp. Konstanten als Konstanten zu schreiben und nicht mit define.> Wie genau macht man das? Willst du in jede C-Datei wo Pi gebraucht wird> einstatic const double pi = 3.1413331233;> schreiben?
Man könnte es in den Header schreiben, genau wie das entsprechende
#define auch.
>> Eine define "Formel" kann man auch als Funktion schreiben.> Auch hier ist die Frage, wie du erreichen willst, dass die Funktion die> gleichen (guten) Eigenschaften hat wie das Makro?
Welches Problem siehst du? Ich sehe nur eins mit so Dingen wie
1
#define MAX(a, b) ((a) > (b) ? (a) : (b))
weil man daraus für jeden Datentyp eine eigene Funktion machen müsste,
mit eigenem Namen. Aber Veit schreibt ja, dass es für ihn nicht um
"alles oder nichts" geht. Er möchte Makros möglichst vermeiden, nicht
komplett abschaffen.
Veit D. schrieb:> Zum Bsp. Konstanten als Konstanten zu schreiben und nicht mit define.> Eine define "Formel" kann man auch als Funktion schreiben. Das alles> heißt noch lange nicht das man auf sein C verzichten muss.
Das geht in C++. In C ist das oft Overkill, Dummheit oder gar unmöglich,
keine defines zu nehmen. Ein Makro hat ganz andere Eigenschaften als
eine Funktion. Wenn Du kein C magst oder brauchst, dann ist das OK.
Aber Hunde als Haustiere abzulehnen, weil Schlitten von Rentieren
gezogen werden können, wird niemandem gerecht.
Rolf M. schrieb:> Man könnte es in den Header schreiben, genau wie das entsprechende> #define auch.
Nur hat man den Wert dann evtl. mehrfach im RAM und ROM.
Rolf M. schrieb:> Welches Problem siehst du? Ich sehe nur eins mit so Dingen wie#define> MAX(a, b) ((a) > (b) ? (a) : (b))> weil man daraus für jeden Datentyp eine eigene Funktion machen müsste,> mit eigenem Namen.
Wenn man die Funktion nicht mit static inline in nen header packt, muss
man für den Funktionsaufruf zahlen.
Rolf M. schrieb:> Aber Veit schreibt ja, dass es für ihn nicht um> "alles oder nichts" geht. Er möchte Makros möglichst vermeiden, nicht> komplett abschaffen.
Und als Beispiel dafür wählt er zwei Beispiele, ohne zu sagen, wann und
wie man das machen kann.
Rolf M. schrieb:> Welches Problem siehst du?
Alles wo # oder ## drin vorkommt.
Alles was im präprozessor passieren muss.
Alles wo 2 token zu einem verschmelzen sollen, ohne ein eigenes Objekt
zu erschaffen.
mh schrieb:> Rolf M. schrieb:>> Man könnte es in den Header schreiben, genau wie das entsprechende>> #define auch.> Nur hat man den Wert dann evtl. mehrfach im RAM und ROM.
Kommt auf das Optimierungsverhalten des Compilers an. Und bei #define
hat man das Problem auch. Die Problematik mit const ist eher, dass man
es nicht überall einsetzen kann, wo ein #define ginge, weil es eben nur
eine Variable ist, die sich nicht ändert und kein konstanter Ausdruck,
wie es in C++ wäre.
Auf https://en.cppreference.com/w/c/language/const ist es ganz gut
zusammengefasst:
"C adopted the const qualifier from C++, but unlike in C++, expressions
of const-qualified type in C are not constant expressions; they may not
be used as case labels or to initialize static and thread storage
duration objects, enumerators, or bit field sizes. When they are used as
array sizes, the resulting arrays are VLAs."
> Wenn man die Funktion nicht mit static inline in nen header packt, muss> man für den Funktionsaufruf zahlen.
Ja, also wenn man sie nicht dorthin schreibt, wo auch das Makro stehen
müsste. Aber seit LTO gilt das auch nicht mehr unbedingt.
Hallo,
Rolf hat mich verstanden.
Es geht um Code den man selbst schreibt. Aber ich bin kein Missionar,
wollte es nur mal erwähnt haben.
Bsp., nur die assert Meldung bekomme ich nicht hin, dass ginge in C++
mit static_assert ganz einfach.
Veit D. schrieb:> Es geht um Code den man selbst schreibt.
Natürlich. Auf anderen hat man wenig Einfluss.
> Bsp., nur die assert Meldung bekomme ich nicht hin, dass ginge in C++> mit static_assert ganz einfach.
Je nach Compiler mit 0, -1 oder einfach nur anders
1
#define static_assert(exp) extern int _d[exp?1:-1]
Und klar, natürlich ist es sinnlos, für die Baudrate ein #define zu
nehmen, wenn Du es direkt in Code schreiben kannst. Das hat aber nichts
mit #define vs Funktion zu tun.
Und natürlich ist es auch sinnlos, ein #define zu nehmen, wenn man
stattdessen eine inline-Funktion nehmen kann. Das wäre so sinnfrei, wie
a+a+a+a+a+a statt 6*a um die Multiplikation zu sparen.
Veit D. schrieb:> Bsp., nur die assert Meldung bekomme ich nicht hin, dass ginge in C++> mit static_assert ganz einfach.Veit D. schrieb:> Hallo,>> Rolf hat mich verstanden.> Es geht um Code den man selbst schreibt. Aber ich bin kein Missionar,> wollte es nur mal erwähnt haben.> [...]
Was genau soll der Quelltext zeigen? Wenn ich mir das fehlende
1
constuint32_tF_CPU=16000000;
2
externvolatilecharUBRR0;
hinzufüge, produziert der Compiler nen haufen Code (350 Zeilen + calls
in die Floatingpoint-Lib), der zur Laufzeit ausgeführt werden muss.
Veit D. schrieb:> Bsp., nur die assert Meldung bekomme ich nicht hin, dass ginge in C++> mit static_assert ganz einfach.
Ja das geht in C++ ganz einfach, dafür muss man allerdings erstmal den
ganzen anderen Kram richtig machen.