Long effizient schreiben

OP #2503539
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...
Gast #2503570
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.
Moderator Persönliche Seite #2503572
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
#2504807
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?
Gast #2504869
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
Moderator Persönliche Seite #2504904
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
#2504911
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.