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
Oli schrieb:> Aber das dauert doch relativ lange
Vermutet oder tatsächlich (also im Assemblercode geprüft)?
Neuesten Compiler benutzt (naja, wenigstens 4.7.2)?
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.
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.
> 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.
>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!
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
externvoiddosomething(uint8_th,uint8_tl);
4
5
void
6
doit(uint16_ti)
7
{
8
dosomething(i>>8,i);
9
}
dann wird da auch nichts geschoben oder gerechnet:
Uwe schrieb:>> unabhängig von der verwendeten CPU!> Nö, nicht ohne Barrel-Shifter oder Harware Multipliziereinheit
wozu sollte man hier einen hardware shifter oder einen Multiplizier
brauchen?
Ok, shiften statt Bytezugriff.
Aber was macht der HW Multiplizierer?
Dividiert der durch 256, wenn man ihn andersrum an die
Versorgungspannung anschließt?
> 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.
Uwe schrieb:>> mov r22,r24>> mov r24,r25>> jmp dosomething> Ich dachte unabhängig von der verwendeten CPUOli schrieb:> ich wäre über eine kleine Hilfe froh (Atmel Studio / GCC).
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.
Uwe schrieb:>> mov r22,r24>> mov r24,r25>> jmp dosomething> Ich dachte unabhängig von der verwendeten CPUARM, -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.
Und (mal wieder) das gleiche Resultat wie in allen vorherigen, ähnlichen
Threads: Die (sowohl von der Ausführungszeit als auch Portabilität)
beste Variante ist die allererste im Ursprungspost gegebene.
Da gibts praktisch keine Diskussion drüber.
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
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.
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
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.
Jörg Wunsch schrieb:> Sofern du die Toolchain auch separat bekommen kannst, sollte das> schon gehen, dass du sie auch der älteren Version „unterschiebst“.
einfach bei Atmel downloaden.
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.