Hallo,
ich versuche eine Verknüpfung im Präprozessor zu machen, klappt
irgendwie nicht so wirklich
1
#define SET_SW1(rechts, stop) \
2
{ \
3
if (stop) \
4
{ \
5
DIS_SW1; \
6
7
OCR1A=NULL; \
8
OCR2B=NULL; \
9
} \
10
else
11
{
12
EN_SW1; \
13
14
if(rechts) \
15
{ \
16
OCR1A=decoder.system.switch1.dimmvalue; \
17
OCR2B=NULL; \
18
} \
19
else \
20
{ \
21
OCR1A=NULL; \
22
OCR2B=decoder.system.switch1.dimmvalue; \
23
} \
24
} \
25
}
Wenn ich nur normale Ausführungen reinschreibe (bspw DDRB = 0\ DDRC = 3\
etcc...) dann geht das.
Eigentlich wollte ich das auch ganz gerne so haben, dass dort keine
echte if-else sondern wiederum eine #if #else ist, sodass an den
Programmstellen nur direkt die 2-3 Zeilen Zuweisung der Register
eingefügt werden, und nicht nochmal mit unterverweigung.
Im Programm steht dann nur sowas wie: SET_SW1(TRUE, FALSE)
Das sind Leezeilen im Code, die beenden das Makro:
1
#define SET_SW1(rechts, stop) \
2
{ \
3
if (stop) \
4
{ \
5
DIS_SW1; \
6
<---- Leerzeile ohne Backslash
7
OCR1A=NULL;\
Nimm die mal raus.
Marius D. schrieb:> Eigentlich wollte ich das auch ganz gerne so haben, dass dort keine> echte if-else sondern wiederum eine #if #else ist,
Kann man machen, dann brauchts aber IMO mehrfaches Parsen. Der Optimizer
schmeisst aber ein if (0) raus, bzw. den else {} Teil bei if (1).
Marius D. schrieb:> Eigentlich wollte ich das auch ganz gerne so haben, dass dort keine> echte if-else sondern wiederum eine #if #else ist, sodass an den> Programmstellen nur direkt die 2-3 Zeilen Zuweisung der Register> eingefügt werden, und nicht nochmal mit unterverweigung.
Das bringt zwar eher nachteile, müsste aber machbar sein.
Ungetestet:
PittyJ schrieb:> Warum geht nicht eine normale Funktion?> Die ist übersichtlicher, wartbarer, und der Autor muss nicht denken.
Kostet mir zu viel Zeit + Speicher.
Daniel A. schrieb:> Das bringt zwar eher nachteile, müsste aber machbar sein.
Danke, ich werde es später testen. Warum bringt das Nachteile? Der
Compiler setzt doch dort einfach die Zeilen hin (wie ein define), das
sollte doch exakt der gleiche Code sein, als wenn ich an den Stellen das
dort manuell hinschreibe.
Marius D. schrieb:> Kostet mir zu viel Zeit + Speicher.
Gemessen oder geraten?
Ansonsten: inline-Funktion.
„Zu viel Zeit + Speicher“ ist ohnehin suspekt: wenn man schnell sein
will, braucht man in der Regel mehr Speicher (inlining, egal ob nun
als inline-Funktion oder durch einen Makro).
Wer solch einen Präprozessor-Spaghetti im 21. Jahrhundert noch baut,
sollte schon 1.) triftige Gründe dafür haben und 2.) in der Lage
sein, ihn auch syntaktisch korrekt niederzuschreiben (siehe Leerzeile).
Ich weiß nicht so recht.
Also Ich bin ja nun wahrlich selber einer der gelegentlich ner wirklich
nützlichen Makrokonstruktion nicht abgeneigt ist, meistens dann wenn sie
einem Arbeit spart meist für Sachen die man in C einfach nicht
vernünftig hinschreiben kann, aber das Ding da oben halte ich wirklich
keinesfalls auch nur annähernd für so einen Kandidaten.
Schreib das lieber mal als inline Funktion und beachte wie das dann
einfacher zu schreiben, zu lesen, zu warten ist, wie es annähernd oder
gar exakt den selben Code erzeugen wird und wie Du unterm Strich kein
bisschen Ersparnis oder Erleichterung gehabt hättest mit diesem Makro.
Marius D. schrieb:> Daniel A. schrieb:>> Das bringt zwar eher nachteile, müsste aber machbar sein.>> Danke, ich werde es später testen. Warum bringt das Nachteile? Der> Compiler setzt doch dort einfach die Zeilen hin (wie ein define), das> sollte doch exakt der gleiche Code sein, als wenn ich an den Stellen das> dort manuell hinschreibe.
Ja, schon, aber das Macro setzt voraus, dass TRUE oder FALSE übergeben
werden, dass TRUE und FALSE nicht durch ein define verändert wurden, und
kann nicht mit Variablen verwendet werden. Zudem bringt es vermutlich zu
eingeschalteter -O3 und -ffunc-section kein Platz oder Performance
Gewinn gegenüger einer gewönlichen funktion, jedenfalls keinen
Signifikanten.
Ich sliesse mich daher den anderen an, dass hier eine Funktion das beste
wäre. Da hier TUE und FALSE sowiso nicht variabel sind, könntest du
eigentlich auch einfach 3 Defines oder 3 Funktionen machen, sollte aber
keine grossen unterschiede machen.
Daniel A. schrieb:> eingeschalteter -O3
Vorsicht: -O3 optimiert sehr aggressiv auf maximale Geschwindigkeit,
ohne Rücksicht auf die Codegröße. Da werden dann Schleifen entrollt,
was das Zeug hält etc. pp.
Ich habe immer nur -01 als Optimierung.
Habe es jetzt mit inline gemacht, war tatsächlich doch kleiner als das
Macro von oben, aber im Endeffekt sollte es auch nicht größer sein, von
daher ist alles gut jetzt.
Marius D. schrieb:> Ich habe immer nur -01 als Optimierung.
Warum?
Einserseits willst Du Zeit und Flash sparen durch krude
Quelltextverunstaltungen, andererseits verbietest Du dem Compiler die
meisten Optimierungen.
Ich empfehle normalerweise -Os -flto.
Bernd K. schrieb:> Marius D. schrieb:>> Ich habe immer nur -01 als Optimierung.>> Warum?>> Einserseits willst Du Zeit und Flash sparen durch krude> Quelltextverunstaltungen, andererseits verbietest Du dem Compiler die> meisten Optimierungen.>> Ich empfehle normalerweise -Os -flto.
Optimierung auf Teufel komm raus ist bei komplexen Programmen (zumindest
was ich für Erfahrungen gemacht habe) einfach nur scheiße.
Tlws. macht er dann was völlig anderes als programmiert (lässt bspw.
Schleifen weg, verkürzt die weil er denkt es wird gesprungen o.ä.) und
nicht immer ist dadurch der Code wirklich kleiner. Ich habe die
Erfahrung gemacht (auf komplexere Programme bezogen), ist es mit -O1 am
kleinsten. Wenn man was größeres nimmt wird's wieder etwas größer. Kommt
aber stark auf das Programm an. Beim Bootloader hat das was gebracht auf
maximum, sogar extrem viel. Aber das Programm besteht auch hauptsächlich
aus mehreren Abfragen und 2 Schleifen. Wenn man viel Strinverarbeitungen
bspw. hat habe ich nicht so gute Erfahrungen damit gemacht.
Marius D. schrieb:> Tlws. macht er dann was völlig anderes als programmiert
Dann ist es falsch programmiert.
Außer dem Timing und der Codegröße sollte sich die grundlegende
Funktion des Codes durch die Optimierung nicht ändern.
Marius D. schrieb:> Tlws. macht er dann was völlig anderes als programmiert (lässt bspw.> Schleifen weg, verkürzt die weil er denkt es wird gesprungen o.ä.)
Das mach doch nichts?! Konstrukte die für die Funktion nicht relevant
sind und die das Ergebnis nicht beeinflussen kann man weglassen.
Eingabe und Ausgabe eines Programmfadens bleiben gleich und das ist
die einzige Garantie die ein C-Compiler überhaupt geben kann und soll.
Mehr soll er nicht. Und das ist auch das einzige worauf es ankommt. Und
wie der Compiler das macht bleibt ihm überlassen.
Wenn Du Unterschiede in den Ausgaben des Programms bemerkst hast Du
vermutlich vergessen alle Eingaben und Ausgaben als solche zu
deklarieren oder Du hast anderweitig grob geschlampt (undefiniertes
Verhalten, nicht initialisierte Variablen, etc.) und wenn Du dann ohne
Optimierung trotzdem richtige Ergebnisse bekommst ist das nur das
Ergebnis einer Verkettung bemerkenswerter Zufälle.
Wenn Dein Programm bei anderen Optimierungseinstellungen oder mit einem
anderen Compiler nicht mehr funktioniert dann ist das der Tatsache
geschuldet daß es aufgrund seiner Fehlerhaftigkeit eigentlich überhaupt
nie hätte funktionieren müssen.
Marius D. schrieb:> Optimierung auf Teufel komm raus ist bei komplexen Programmen (zumindest> was ich für Erfahrungen gemacht habe) einfach nur scheiße.
Meine Erfahrung ist, dass das in der Regel nicht an der Komplexität,
sondern an Fehlern im Programm oder fehlerhaften Annahmen durch den
Programmierer liegt, was ich auch hier vermute:
> Tlws. macht er dann was völlig anderes als programmiert (lässt bspw.> Schleifen weg, verkürzt die weil er denkt es wird gesprungen o.ä.)
Viele sind sich der as-if-Regel nicht bewusst, die aber eigentlich in
diesem Zusammenhang essenziell ist. Die besagt, dass der Compiler den
Code beliebig verändern darf, solange das "observable behaviour", also
das beobachtbare Verhalten gleich bleibt. Und das ist definiert als
File-Zugriffe und Zugriffe auf volatile-Variablen. Alles andere darf der
Compiler beliebig verändern - auch das Timing, solange nur die oben
besagten Zugriffe alle noch da sind und in der richtigen Reihenfolge
durchgeführt werden.
Von dieser Regel macht vor allem der Optimizer regen gebrauch. Sein Ziel
ist, den Code so schnell und/oder klein wie möglich zu machen, ohne dass
sich das beobachtbare Verhalten ändert. Alles, was dafür nicht benötigt
wird, schmeißt er deshalb raus.
Ein typischer Fehler, der daraus resultiert, sind zum Beispiel
"Warteschleifen", wo eine leere for-Schleife geschrieben wird und der
Programmierer sich wundert, warum der Compiler die verwirft. Nun, da sie
keinen Effekt hat außer Platz und Zeit zu verbrauchen, schmeißt der
Optimizer sie raus, denn der ist ja gerade dazu da, den Platz- bzw.
Zeitverbrauch zu minimieren.