Funkt soweit.
Nun sind aber nicht alle möglichen Argumentenpaare vorgesehen. Anders
ausgedrückt, für eine bestimmte Kombination von foo und bar soll kein
Makro existieren.
Gleichzeitig möchte ich aber vorm Benutzer verstecken, dass er zwei
Argumente übergeben soll.
Der Benutzer soll nur eine Liste an möglichen Wertepaaren kennen.
Dazu würde ich gerne die Paare "kapseln", z.B. so:
1
#define arg1 (1, 3)
2
#define arg2 (5, 2)
3
[/c}
4
5
Verwendung:
6
[c]
7
...
8
val=myMakro(arg1);
9
...
Und hier meckert mir der Compiler:
"too few arguments in macro invocation".
Vermutlich löst er arg1 nicht auf und sieht deswegen nur ein Argument
für myMakro?
Weiß hier wer weiter?
Viele Grüße,
jack
jack schrieb:> Vermutlich löst er arg1 nicht auf und sieht deswegen nur ein Argument> für myMakro?
Mach mal einen einfachen Textersatz und zähle die Klammern:
val = myMakro(arg1);
wird zu
val = myMakro((1 , 3));
Rufus Τ. Firefly schrieb:> Mach mal einen einfachen Textersatz und zähle die Klammern:>> val = myMakro(arg1);>> wird zu>> val = myMakro((1 , 3));
Ja, das hab ich mir auch schon gedacht.
Aber wie würds dann gehn?
#define arg1 1,3
bringt genauso wenig.
Ja, auch die sind mir bekannt. (Ok, zwar noch nie benutzt, aber ich weiß
das sowas existiert)
Und meiner Meinung nach sind die nicht das, was ich brauche.
Ich will nicht ein Makro manchmal mit einem, manchmal mit zwei
Argumenten aufrufen.
Stattdessen soll das Makro arg1 (was für den Benutzer aussieht wie 1
Argument) expandieren zu einer vorgegebenen Argumentenliste, z.B. "1,3".
So wie ich das sehe helfen mir hier Variadic Makros doch auch nicht
weiter.
Genauso wie der oben verlinkte Beitrag. Der TE hatte ja eher das
umgekehrte Problem.
Aus 2 Argumenten eines machen, dabei hilft ##.
Grüße, jack
Makros machen mehr Probleme als die sie lösen. Deshalb verwende ich seit
Jahren keine Makros mehr und fahre sehr gut damit.
Vielleicht einfach mal versuchen, ob das nicht auch ohne Makro geht?
Ich verwende sie auch sehr ungern.
Deswegen hab ich da wohl auch solche Defizite :-)
Hab letztens wieder Code gesehn der vor Makros nur so triefte. Da waren
sogar Funktionsparameter hinter Makros versteckt. Sowas macht Spaß zu
debuggen :/ Vom ##-Operator mal ganz zu schweigen, der macht Suchen
immer so schön unmöglich.
In diesem Fall hab ich durch ein Function-like Makro allerdings einen
erheblichen Performancevorteil.
Ich muss nur schauen dass ich das Interface so hinkriege, dass man es
theoretisch doch mal durch eine Funktion ersetzen könnte.
PittyJ schrieb:> Makros machen mehr Probleme als die sie lösen.
Bei mir ist es genau das Gegenteil. Macros sinnvoll eingesetzt erhöhen
die Lesbarkeit enorm.
Auch helfen sie, Fehler zu vermeiden, weil man etwas nicht mehr
umständlich schreiben muß.
Peter
jack schrieb:> In diesem Fall hab ich durch ein Function-like Makro allerdings einen> erheblichen Performancevorteil.
Als Ersatz für function-like Makros gibt es Inline-Funktionen.
Yalu X. schrieb:> Als Ersatz für function-like Makros gibt es Inline-Funktionen.
wenn der Compiler so gnädig ist und sich an den Vorschlag hält,
umgekehrt inlined er ja auch manchmal von sich aus eine Funktion die
ganz "normal" deklariert ist
Walter S. schrieb:> wenn der Compiler so gnädig ist und sich an den Vorschlag hält,
GCC? --> always_inline
Generally, functions are not inlined unless optimization is
specified. For functions declared inline, this attribute inlines the
function even if no optimization level was specified.
http://gcc.gnu.org/onlinedocs/gcc-4.0.4/gcc/Function-Attributes.html
Yalu X. schrieb:> Als Ersatz für function-like Makros gibt es Inline-Funktionen.
Ich muss gestehen, ich habe mich bisher recht wenig mit
inline-Funktionen beschäftigt. Ich dachte mir immer, der Compiler wird
schon wissen was er macht :-)
Wie schauts denn bei inline mit dem Scope aus? Angenommen ich mache
meinem Programm über einen Header eine inline-Funktion bekannt (Bzw.
deren Prototyp).
Diese Funktion wird von meinem Hauptprogramm aufgerufen.
Nun greift diese Funktion aber auf eine Modul-interne (=static) Variable
zu, meinetwegen einen internen Zustand oder irgend-sowas.
Diese Wird natürlich in der .c-Datei des Moduls definiert.
So, jetzt "inlined" der Compiler meine Funktion ins Hauptprogramm. Sieht
die Funktion nun diese "globale" Variable?
Und noch weiter:
In meiner inline Funktion habe ich eine Zählervariable "i".
Und weil mir "i" als Name sogut gefällt benutz ich diesen auch im
Hauptprogramm. Beisst sich das?
Viele Grüße, jack
jack schrieb:> Wie schauts denn bei inline mit dem Scope aus? Angenommen ich mache> meinem Programm über einen Header eine inline-Funktion bekannt (Bzw.> deren Prototyp).> Diese Funktion wird von meinem Hauptprogramm aufgerufen.>> Nun greift diese Funktion aber auf eine Modul-interne (=static) Variable> zu, meinetwegen einen internen Zustand oder irgend-sowas.> Diese Wird natürlich in der .c-Datei des Moduls definiert.>> So, jetzt "inlined" der Compiler meine Funktion ins Hauptprogramm. Sieht> die Funktion nun diese "globale" Variable?
Damit der Compiler die Funktion überhaupt inlinen kann, muss auch die
Implementierung der Funktion in der Header-Datei stehen. Es ist also so,
als würde Funktion direkt in der C-Datei (oder den C-Dateien) stehen, in
der sie geinlined wird, und kann somit natürlich auch auf die Variablen
in diesen jeweiligen Modulen zugreifen. Die Inline-Funktion hat kein
"eigenes" Modul.
jack schrieb:> In meiner inline Funktion habe ich eine Zählervariable "i".> Und weil mir "i" als Name sogut gefällt benutz ich diesen auch im> Hauptprogramm. Beisst sich das?
Kein Problem. Auch eine Inline-Funktion ist formal natürlich eine
normale Funktion mit normalen lokalen Variablen.
Noch eine kleine Ergänzung zu Ernsts Tipps bzgl. der Inline-Funktionen:
Am besten deklariert man sie als static. Sonst generiert der Compiler
zusätzlich zu den geinlineten Code-Fragmenten auch noch ein "echtes"
Unterprogramm, weil er davon ausgehen muss, dass die Funktion auch von
anderen Programmmodulen aufgerufen wird. Da dies aber nicht der Fall
ist, kann man mit dem static den Programmcode etwas vekleinern.
Yalu X. schrieb:> Noch eine kleine Ergänzung zu Ernsts Tipps bzgl. der Inline-Funktionen:> Am besten deklariert man sie als static.
Also der AVR-GCC meckert bei nicht static Inline-Funktionen.
Das heimliche Inlinen schalte ich immer aus, da verschätzt sich der
AVR-GCC völlig:
1
-fno-inline-small-functions
Er müßte ja die Codegröße ins Verhältnis setzen zu der Anzahl der
Aufrufe und das tut er nicht.
Peter
?
Letztlich kann der Compiler sich meines Wissens nach sowohl entscheiden
Inline-Funktionen nicht zu inlinen als auch selbständig normale
Funktionen inlinen. Hat das Wort "inline" dann überhaupt eine Bedeutung,
außer vielleicht je nach Optimierungseinstellung die
Inline-"Wahrscheinlichkeit" zu verändern?
Peter Dannegger schrieb:> Das heimliche Inlinen schalte ich immer aus, da verschätzt sich der> AVR-GCC völlig:> -fno-inline-small-functions> Er müßte ja die Codegröße ins Verhältnis setzen zu der Anzahl der> Aufrufe und das tut er nicht.
Verstehe ich nicht. Das Inlinen von sehr kleinen Funktionen verringert
doch sowohl Codegröße als auch Ausführungszeit.
xfr schrieb:> Das Inlinen von sehr kleinen Funktionen verringert> doch sowohl Codegröße als auch Ausführungszeit.
Wie soll das gehen?
Inlinen vergrößert den Code, außer die Funktion wird nur einmal
aufgerufen.
Inlinen ist ja quasi copy&paste und daher immer größer als nur ein
weiterer RCALL.
Die Entscheidung für das heimliche Inlinen trifft der GCC nicht auf den
AVR optimiert. Daher wird oft relativ großer Code geinlined.
Wenn eine Funktion sehr oft benötigt wird, kann das Inlinen also
deutlich mehr Code bewirken.
Wenn Du verreist, packst Du Dir einen Koffer.
Inlinen heiß dann, für die nächste Reise kaufst Du einen neuen Koffer
mit neuem Inhalt und schmeißt den alten weg.
Der Compiler hat nun aber schlechte AVR-Augen und sieht den Koffer als
sehr klein an. D.h. er meint, es lohne sich nicht den alten aufzuheben
und kauft einen neuen. Daher mußt Du ihm das explizit verbieten.
Peter
Peter Dannegger schrieb:> Wie soll das gehen?> Inlinen vergrößert den Code, außer die Funktion wird nur einmal> aufgerufen.> Inlinen ist ja quasi copy&paste und daher immer größer als nur ein> weiterer RCALL.
Du musst ja vorher noch die Parameter in den richtigen Registern haben
bzw. auf den Stack legen und nach Aufruf wieder auswerten. Ein Funktion
wie
1
staticuint8_tadd(uint8_ta,uint8_tb)
2
{
3
returna+b;
4
}
ist als Funktionsaufruf viel aufwändiger als sie zu inlinen, egal wie
oft sie verwendet wird. Außerdem kann der Compiler ohne Funktionsaufruf
das ganze vielleicht sogar völlig wegoptimieren, wenn z.B. zwei
konstante Werte verwendet werden. Solche Funktionen sind mit "small
functions" gemeint.
xfr schrieb:> Hat das Wort "inline" dann überhaupt eine Bedeutung,> außer vielleicht je nach Optimierungseinstellung die> Inline-"Wahrscheinlichkeit" zu verändern?
Ja, genau das ist es. Ist so, wie früher die Speicherklasse "register",
die auch einen Hinweis an den Compiler darstellte, eine "auto"-
Variable bevorzugt in einem CPU-Register zu halten.
Eine modulinterne Funktion ("static"), die nur einmal gerufen wird,
expandiert der GCC bei eingeschalteter Optimierung immer inline.
xfr schrieb:> Solche Funktionen sind mit "small> functions" gemeint.
Den Eindruck habe ich aber nicht. Mir inlined er auch häufig benutzte
teure Funktionen, die den Code explodieren lassen.
Mag sein, daß er manchmal auch günstig inlinen kann, aber das wirkt sich
nicht spürbar aus. Man merkt nur die großen Brocken.
Der Schalter (-fno...) ergibt bei mir immer den kleineren Code.
Peter
xfr schrieb:> Was ist eigentlich der Unterschied zwischen:static inline uint8_t
meine_funktion(uint8_t var);undstatic uint8_t meine_funktion(uint8_t var);?
Ohne nachgeschlagen zu haben: vermutlich ist es nicht zulässig, auf als
inline deklarierten Funktionen den Adreßoperator anzuwenden.