Wie Umwandlung von Integer -> 2xByte beschleunigen?

Gast #3121469
Lesenswert?

Hallo,
ich wäre über eine kleine Hilfe froh (Atmel Studio / GCC).

Ich habe eine unsigned Integer Variable und möchte auf die beiden 
enthaltenen Bytes (MSB / LSB) separat zugreifen.

Das geht natürlich so:

Byte1 = (Integervariable >> 8) & 0xff;
Byte2 = Integervariable & 0xff;

Aber das dauert doch relativ lange, vor allem, da ich das in einer 
Schleife häufig machen muss.

Gibt es keine Möglichkeit das vorher irgendwie zu definieren, so dass 
ich keinen Zeitverlust beim Zugriff habe?

Also z.B. dass "Integervariable" und "Byte1" und "Byte2" den gleichen 
Adressraum belegen und ohne Rotation und Und-Verknüpfung abgegriffen 
werden können?

Soll heißen, wenn ich 1111000000111 in "Integervariable" schreibe, 
stehen in
Byte1: 11110000 und in
Byte2: 00001111.

Wenn nein, hat jemand noch eine Idee zur Beschleunigung?

Danke !!!

Oli
Gast #3121517
Lesenswert?

Mach ne Union. Dabei wird nicht gerechnet bzw. geschoben, sondern die
Variablen in den gleichen Speicherbereich gelegt.

    union conv{
      unsigned char c[2];
      int i;
    } r;

conv a;

a.i=7855;

danach kannst du auf a.c[0] und a.c[1] jeweils auf low und high byte 
zugreifen. Oder andersherum a.c[1] verändern und auf a.i zugreifen.
Gast #3121524
Lesenswert?

Uwe schrieb:
> Mach ne Union. Dabei wird nicht gerechnet bzw. geschoben, sondern die
> Variablen in den gleichen Speicherbereich gelegt.
>
>     union conv{
>       unsigned char c[2];
>       int i;
>     } r;
>
> conv a;
>
> a.i=7855;
>
> danach kannst du auf a.c[0] und a.c[1] jeweils auf low und high byte
> zugreifen. Oder andersherum a.c[1] verändern und auf a.i zugreifen.

und es kommt je architektur der cpu was anders raus und es nicht mal 
definiert was raus kommt.
Gast #3121543
Lesenswert?

> und es kommt je architektur der cpu was anders raus und es nicht mal
> definiert was raus kommt.
Jo aber dafür schnell. Was anderes war ja nicht gefordert bzw. die 
kompatible Lösung stand ja schon da.
Gast #3121572
Lesenswert?

>Das geht natürlich so:
>Byte1 = (Integervariable >> 8) & 0xff;
>Byte2 = Integervariable & 0xff;

Mit einem halbwegs vernünftigem Compiler und eingeschalteter Optimierung 
ist die obige Variante eben so schnell aber zudem auch noch portierbar, 
unabhängig von der verwendeten CPU!
Moderator Persönliche Seite #3121636
Lesenswert?

Uwe schrieb:
> Mach ne Union. Dabei wird nicht gerechnet bzw. geschoben

Keiner sagt, dass bei >> zwingend was gerechnet oder geschoben werden
muss.  Daher habe ich ja auch als erstes gefragt, ob er's denn auch
tatsächlich probiert hat.

Wenn du bspw. sowas hast:
1
#include <stdint.h>
2

3
extern void dosomething(uint8_t h, uint8_t l);
4

5
void
6
doit(uint16_t i)
7
{
8
        dosomething(i >> 8, i);
9
}

dann wird da auch nichts geschoben oder gerechnet:
1
.global doit
2
        .type   doit, @function
3
doit:
4
/* prologue: function */
5
/* frame size = 0 */
6
/* stack size = 0 */
7
.L__stack_usage = 0
8
        mov r22,r24
9
        mov r24,r25
10
        jmp dosomething
Gast #3121665
Lesenswert?

>        mov r22,r24
>        mov r24,r25
>        jmp dosomething
Ich dachte unabhängig von der verwendeten CPU

> Dividiert der durch 256
Je nachdem in welche Richtung gewandelt werden soll (char zu integer 
high byte) bzw. Big- oder Little-endian.
Moderator Persönliche Seite #3121697
Lesenswert?

Der schrieb:
> Du kannst auch einen einen Byte Pointer verwenden...

Der wäre effektiver als der Schiebeoperator, meinst du?

Hast du dir obigen compilierten Assemblercode mal angesehen?  Ich
frage mich ernsthaft, warum hier noch jemand 1023 andere Varianten
haben möchte, wenn die generische offensichtlich (zumindest mit
einem aktuellen Compiler und natürlich mit eingeschalteter
Optimierung) prima funktioniert.
Moderator Persönliche Seite #3121730
Lesenswert?

Uwe schrieb:
>>        mov r22,r24
>>        mov r24,r25
>>        jmp dosomething
> Ich dachte unabhängig von der verwendeten CPU

ARM, -mthumb -mcpu=cortex-m3:
1
        .type   doit, %function
2
doit:
3
        @ args = 0, pretend = 0, frame = 0
4
        @ frame_needed = 0, uses_anonymous_args = 0
5
        @ link register save eliminated.
6
        mov     r1, r0
7
        uxtb    r1, r1
8
        lsrs    r0, r0, #8
9
        b       dosomething

Dort bleibt ihm natürlich nichts anderes übrig, als auch 8 bits zu
schieben, aber das wäre auch mit einer Union nicht anders.  Dafür
wiederum geht die Schiebeoperation auf dem Cortex-M3 schnell.
Gast #3122457
Lesenswert?

Danke für Euer Feedback.
Ich wusste nicht, dass der GCC Compiler das optimiert. Ich probiere das 
mal im Vergleich zu der union-Variante aus.

Führt er diese erwähnte Optimierung in allen Optimierungsstufen durch, 
oder erst in höheren?

Danke
oli
Moderator Persönliche Seite #3122475
Lesenswert?

Oli schrieb:

> Ich wusste nicht, dass der GCC Compiler das optimiert. Ich probiere das
> mal im Vergleich zu der union-Variante aus.

Was sollte sich denn bei der Union noch ändern?

Btw., ich hab's für dem ARM-GCC auch mit einer Union probiert.
Außer, dass man sich dann die besagten Byteorder-Probleme einhandelt
(stehen die höheren 8 Bit nun in b[1] oder in b[0]?), ergab sich kein
Unterschied im generierten Code.

Wichtig: nimm den GCC 4.7.2.  Falls du die Atmel-Toolchain benutzt,
dann musst du die allerletzte Version nehmen, alle davor hatten einen
recht alten (und teilweise buggigen) Compiler dabei.

> Führt er diese erwähnte Optimierung in allen Optimierungsstufen durch,
> oder erst in höheren?

Naja, mit -O0 natürlich nicht. ;-)  Aber ab -O1 schon.  Für den AVR-GCC
ist in der Praxis -Os erfahrungsgemäß die Optimierungsstufe, mit der
man erstmal ins Rennen gehen sollte.
Gast #3122494
Lesenswert?

Danke Jörg,

eine Frage noch: Ich arbeite ja mit Studio 6.0, bis jetzt SP1 - da ist 
die GCC 4.6.2 drin.
Auch in SP2 ist noch nicht der GCC 4.7.2 drin, sondern erst in der neuen 
Atmel Studio 6.1 beta.

Eine Beta will ich mir nun aber nicht gerade installieren, kann ich auch 
nur den GCC ohne Klimmzüge updaten? Wenn ja, wie?

Nochmals Danke
Oli
Moderator Persönliche Seite #3122502
Lesenswert?

Oli schrieb:
> Eine Beta will ich mir nun aber nicht gerade installieren, kann ich auch
> nur den GCC ohne Klimmzüge updaten? Wenn ja, wie?

Keine Ahnung, das fragst du ggf. besser im Forum PC-Hard- und
-Software, denn es ist ja ein reines Problem von Atmel Studio.

Sofern du die Toolchain auch separat bekommen kannst, sollte das
schon gehen, dass du sie auch der älteren Version „unterschiebst“.

Ansonsten kannst du dich ja auch mal im entsprechenden Forum auf
avrfreaks.net umsehen, ob denn die 6.1er Beta-Version überhaupt
nennenswert Späne macht, oder ob sie nicht vielleicht ohnehin eine
Verbesserung gegenüber der alten Version ist, trotz Beta.
#3122517
Lesenswert?

Jörg Wunsch schrieb:
> Ansonsten kannst du dich ja auch mal im entsprechenden Forum auf
> avrfreaks.net umsehen, ob denn die 6.1er Beta-Version überhaupt
> nennenswert Späne macht, oder ob sie nicht vielleicht ohnehin eine
> Verbesserung gegenüber der alten Version ist, trotz Beta.

Die Beta 6.1 verhaut bei mir regelmäßig die Codeformatierung beim 
Kopieren von Code und klappt manchmal willkürlich sämtliche Dependencies 
auf. Würde ich erstmal nicht installieren, lieber nur die Toolchain.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren