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!
> unabhängig von der verwendeten CPU!
Nö, nicht ohne Barrel-Shifter oder Harware Multipliziereinheit
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 |
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 CPU Oli schrieb: > ich wäre über eine kleine Hilfe froh (Atmel Studio / GCC).
Du kannst auch einen einen Byte Pointer verwenden... Little / Big endian Problematik bleibt erhalten.
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 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.
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.