Forum: Compiler & IDEs Long effizient schreiben


von Thomas M. (marod3ur)


Lesenswert?

Hallo,

ich versuche gerade meinen Code zu optimieren und frage mich, welches 
die effizienteste Lösung ist eine Long-Variable aus 4 Bytes zusammen zu 
setzen. Bisher habe ich es so gemacht:
1
long Long;
2
unsigned char Byte1,Byte2,Byte3,Byte4;
3
4
Long   = Byte1 ; Long <<= 8; 
5
Long  += Byte2 ; Long <<= 8;
6
Long  += Byte3 ; Long <<= 8;
7
Long  += Byte4 ; Long <<= 8;

--> also mit Bitverschiebung. Die Frage ist ob es nicht bequemer und vor 
allem schneller geht, sprich mit weniger Taktzyklen.

Vielen Dank...

von Oliver (Gast)


Lesenswert?

Der nicht C-konforme, aber bei den meisten Prozessoren funktionierende 
Hack geht über eine Union.

Oliver

von Heinz (Gast)


Lesenswert?

Eine Union ist das Mittel der Wahl. Die einzelnen Komponente liegen 
übereinandern.


union
{
 unsigned char vByte[ 4 ] ;     //  4 mal unsigned char (4 Bytes)
 long vLong ;                   //  1 mal long          (4 Bytes)
} value ;

value.cByte[0] = 100 ;

etc.

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Thomas M. schrieb:
> Long   = Byte1 ; Long <<= 8;
> Long  += Byte2 ; Long <<= 8;
> Long  += Byte3 ; Long <<= 8;
> Long  += Byte4 ; Long <<= 8;

Der letzte Shift ist hyperfluid und sogar falsch.

Intuitiv dachte ich, dass das Ersetzen von '+' durch '|' effizienter 
sei. Komischerweise generiert der AVR-GCC damit längeren Code...

Das hier geht wesentlich schneller:

    unsigned char * l = (unsigned char *) &Long;
    l[0] = Byte1;
    l[1] = Byte2;
    l[2] = Byte3;
    l[3] = Byte4;

Vorsicht:
Die Reihenfolge des Füllens ist abhängig vom Endian des Prozessors.

Gruß,

Frank

von smoerre (Gast)


Lesenswert?

Heinz schrieb:
> Eine Union ist das Mittel der Wahl.

Eine Union ist höchst unportabel.

von Thomas M. (marod3ur)


Lesenswert?

Vielen Dank für die schnellen Antworten! Werde ich gleich mal testen.

@Frank: Der Fehler mit dem Shiften ist beim Copy and Paste aufgetreten, 
steht so nicht im Quelltext.

Grüße...

von DirkB (Gast)


Lesenswert?

Thomas M. schrieb:
> Der Fehler mit dem Shiften ist beim Copy and Paste aufgetreten,
> steht so nicht im Quelltext.

Dann ist das aber kein Copy&Paste. Denn dadurch sollten diese Fehler 
eben nicht entstehen.

von Thomas M. (marod3ur)


Lesenswert?

Hehe, nein...habe die erste Zeile kopiert und nach unten hin geändert. 
Im richtigen Code heißen die Variablen natürlich ganz anders. Wollte es 
vereinfacht hier im Forum darstellen...

von Simon K. (simon) Benutzerseite


Lesenswert?

Heinz schrieb:
> Eine Union ist das Mittel der Wahl.

Eine Union ist beinahe (?) die schlechteste aller Möglichkeiten.

von Klaus W. (mfgkw)


Lesenswert?

nein.
Das ist sie nur, wenn es um Portabilität geht.
Auf einem Controller ist das eher selten sein.

Den portableren Weg über Shiften kennt er ja, und er will es schneller 
haben.
Dann bleibt noch der gezeigte Weg über die Zeiger und der mit union.

Was gefällt dir daran nicht?

von Thomas M. (marod3ur)


Lesenswert?

Da das Programm später noch auf anderen Controllern ohne großen Aufwand 
laufen können muss, habe ich nun die Variante über den Zeiger gewählt 
und realisiert.

Vielen Dank für die Hilfe

Thomas

von Oliver (Gast)


Lesenswert?

Schlechte Wahl. Die pointer-Lösung basiert auf dem selben Prinzip wie 
die Lösung mit der Union, ist damit genauso wenig portabel, braucht aber 
wesentlich mehr Zyklen.

Wirklich portabel ist nur deine anfangs gezeigte Variante.

Oliver

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Oliver schrieb:
> Schlechte Wahl. Die pointer-Lösung basiert auf dem selben Prinzip wie
> die Lösung mit der Union, ist damit genauso wenig portabel, braucht aber
> wesentlich mehr Zyklen.

Ja, es ist dasselbe Prinzip wie die Lösung mit der Union, ist aber von 
der Schreibarbeit weniger aufwendig. Natürlich hast Du recht: Sie ist 
genauso wenig portabel wie die Union, da beide abhängig vom "Bytesex" 
(Endian) des µCs sind.

Aber im letzten Punkt gebe ich Dir nicht recht. Es kann nicht 
"wesentlich mehr" Zyklen brauchen als die Union-Lösung.

Hier ein Auszug aus der lss-Datei (AVR-gcc):

    unsigned char * l = (unsigned char *) &Long;
    l[0] = Byte1;
  b6:  80 91 61 00   lds  r24, 0x0061
  ba:  80 93 62 00   sts  0x0062, r24
    l[1] = Byte2;
  be:  80 91 60 00   lds  r24, 0x0060
  c2:  80 93 63 00   sts  0x0063, r24
    l[2] = Byte3;
  c6:  80 91 66 00   lds  r24, 0x0066
  ca:  80 93 64 00   sts  0x0064, r24
    l[3] = Byte4;
  ce:  80 91 67 00   lds  r24, 0x0067
  d2:  80 93 65 00   sts  0x0065, r24

Das ist verdammt kurz. Ich wüsste nicht, wo die Union-Lösung da noch ein 
Byte einsparen könnte. Von "wesentlich mehr als die Union-Lösung" kann 
daher keine Rede sein.

> Wirklich portabel ist nur deine anfangs gezeigte Variante.

Ja, leider. Die Shift-Version kostet das 5-7 fache an Code. Ich würde 
trotzdem immer die portable Variante vorziehen, außer man hätte die 
Möglichkeit, den Endian des verwendeten Prozessors per Preprocessor 
abzufragen. Dann könnte man portabel beide Varianten im Source 
platzieren, nämlich in etwa so:

    unsigned char * l = (unsigned char *) &Long;

#if BIG_ENDIAN == 1
    l[0] = Byte1;
    l[1] = Byte2;
    l[2] = Byte3;
    l[3] = Byte4;
#else
    l[0] = Byte4;
    l[1] = Byte3;
    l[2] = Byte2;
    l[3] = Byte1;
#endif

Gruß,

Frank

von Klaus W. (mfgkw)


Lesenswert?

Frank M. schrieb:
> außer man hätte die
> Möglichkeit, den Endian des verwendeten Prozessors per Preprocessor

Geht bei gcc über vordefinierte Makros.
Damit ist man nicht mehr vom System abhängig, sondern nur noch vom gcc, 
was evtl. eine sinnvollere Einschränkung ist.

Ansonsten kann man es auch mit C-Ausdrücken erreichen, die nur konstante 
Ausdrücke verwenden. Damit hat man gute Aussichten, daß der Compiler 
alles wegoptimieren kann und es zur Laufzeit nichts kostet und trotztdem 
portabel ist.

von Peter D. (peda)


Lesenswert?

Frank M. schrieb:
> Die Shift-Version kostet das 5-7 fache an Code.

Wen interessierts.
Wichtig ist nur, ob es sich merkbar auf die Codegröße und 
Ausführungszeit des gesamten Programms auswirkt.

Wenn die portable Version das Programm um 0,01% langsamer macht, nehme 
ich die natürlich.


Peter

von Thomas M. (marod3ur)


Lesenswert?

Ja stimmt, habe ja ganz den Endian vergessen. Hm, dann wird es wohl 
wieder die erste Variante...

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.