Forum: Compiler & IDEs Präprozessor Abfrage Verknüpfung was läuft falsch?


von MOBA 2. (Gast)


Lesenswert?

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)

: Verschoben durch Moderator
von Jim M. (turboj)


Lesenswert?

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).

von Daniel A. (daniel-a)


Lesenswert?

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:
1
#define SET_SW1(rechts, stop) \
2
  SET_SW1_STOP_ ## stop(rechts)
3
4
#define SET_SW1_STOP_TRUE(X) \
5
  { \
6
    DIS_SW1; \
7
    OCR1A = NULL; \
8
    OCR2B = NULL; \
9
  }
10
11
#define SET_SW1_STOP_FALSE(rechts) \
12
  { \
13
    EN_SW1; \
14
    SET_SW1_RECHTS_ ## rechts() \
15
  }
16
17
#define SET_SW1_RECHTS_TRUE() \
18
  OCR1A = decoder.system.switch1.dimmvalue; \
19
  OCR2B = NULL;
20
21
#define SET_SW1_RECHTS_FALSE() \
22
  OCR1A = NULL; \
23
  OCR2B = decoder.system.switch1.dimmvalue;

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Inline-Funktionen schreiben sich weniger krampfig.

von PittyJ (Gast)


Lesenswert?

Warum geht nicht eine normale Funktion?
Die ist übersichtlicher, wartbarer, und der Autor muss nicht denken.

von MOBA 2. (Gast)


Lesenswert?

PittyJ schrieb:
> Warum geht nicht eine normale Funktion?
> Die ist übersichtlicher, wartbarer, und der Autor muss nicht denken.

Kostet mir zu viel Zeit + Speicher.

von MOBA 2. (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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).

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> (siehe Leerzeile).

Nicht nur die, das erste "else" ist auch nicht koscher.

von Bernd K. (prof7bit)


Lesenswert?

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.

: Bearbeitet durch User
von Daniel A. (daniel-a)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von MOBA 2. (Gast)


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

von MOBA 2. (Gast)


Lesenswert?

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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

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.

von Bernd K. (prof7bit)


Lesenswert?

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.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Lesenswert?

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.

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.