www.mikrocontroller.net

Forum: Compiler & IDEs Byte-Zugriff auf 32bit Variable


Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo, hier mein Problem...

ich habe folgende Variablen

ziel  32 Bit
var1  16 Bit
var2  8  Bit
var3  8  Bit

nun will ich alle Variablen "varX" an eine bestimmte Position in die 
Variable "ziel" kopieren. Dabei ist es wichtig, dass so wenig wie 
möglich Rechenzeit benötigt wird.

so soll die Variable Ziel später aussehen (links Bits, rechts welche 
Variable darin sein soll):

 0-7  var3
 8-15 var2
16-31 var1

billig und langsam:
ziel|var1;
ziel<<=8;
ziel|=var2;
ziel<<=8;
ziel|=var3;

gibt es eine Möglichkeit, z.B. var2 direkt in das zweite byte von "ziel" 
zu schreiben, oder geht das nur in assembler (inline)?
Villeicht mit Zeigern ein Byte weiter, geht das?

Der Bereich ist sehr zeitkritisch und daher will ich ihn möglichst 
optimieren, als ich gesehen habe was GCC aus den verschiebeoperationen 
macht wird es einem aber ganz anders...
assembler kann ich zwar aber wenn würde ich das mit inline-assembler 
machen, wovon ich keine Ahnung habe - Da ist mir C doch lieber

Hat wer ne Idee? :)

Gruß,
Kjartan

Autor: Meinereiner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
union

Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wenn ich mich nicht irre, kann ich mit der union hier nichts erreichen.
Mit einer union könnte ich doch auch nur von hinten auffüllen oder irre 
ich mich da?
Bzw. wie soll ich eine 8Bit Variable (ohne Verschiebeoperationen) in das 
zweite Byte einer Variable bringen?

Autor: Tim T. (tim_taylor)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doch, sollte gehen:
#include <stdio.h>
#include <stdlib.h>

union {
 unsigned int ziel;
 struct {
  unsigned char var3;
  unsigned char var2;
  unsigned short var1;
 } quelle;
} daten;

int main(void) {
 daten.quelle.var3=255;
 daten.quelle.var2=255;
 daten.quelle.var1=65535;
 printf("%u\n", daten.ziel);
 system("PAUSE");  
 return 0;
}
Ausgabe ist dann 4294967295.

Musst nur vorher prüfen ob auf deinem Zielsystem die endianess stimmt 
und wie groß die entsprechenden Datentypen sind...

Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
super danke (allgemeinbildung++)

aber meine "Variablen" var1,var2,var3 sind Register von AVR Modulen -.-

Hat noch wer ne Idee, oder sollte ich mir besser inline-assembler zu 
herzen nehmen?

Autor: gsdfgsd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sind die Register verstreut? Gib mal Detailinformationen, was wo liegt

Autor: Bernhard R. (barnyhh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kjartan Ferstl schrieb:
>> aber meine "Variablen" var1,var2,var3 sind Register von AVR Modulen -.-
>>
>> Hat noch wer ne Idee, oder sollte ich mir besser inline-assembler zu
>> herzen nehmen?

Du bist offensichtlich ein absoluter Anfänger. Höre bitte auf, 
Schlagwörter zu verwenden und lerne stattdessen!

Bernhard

Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bernhard R. schrieb:
> Kjartan Ferstl schrieb:
>>> aber meine "Variablen" var1,var2,var3 sind Register von AVR Modulen -.-
>>>
>>> Hat noch wer ne Idee, oder sollte ich mir besser inline-assembler zu
>>> herzen nehmen?
>
> Du bist offensichtlich ein absoluter Anfänger. Höre bitte auf,
> Schlagwörter zu verwenden und lerne stattdessen!
>
> Bernhard

du bist offensichtlich ein absoluter "Profi". Also hör bitte auf,
Schalgwörter zu verwenden um Leute einzustufen. Wenn du Theads ansiehst 
nur um andere zu kritisieren bist du hier (glaube ich) an der flaschen 
Stelle.

Hättest du meine Angabe gelesen, so müsste dir klar sein, dass ich nicht 
gefragt habe: wie lege ich meine Variablen am besten an um möglichst 
viel Tricksen zu können.
Nein, ich fragte ob es möglich ist, eine 8-byte Variable auf das 2. byte 
einer 32 bit Variablen zu schreiben.
Eine union ist aber alles andere als verschiedene Variablen.

Dass es sich im falle meiner "Variablen" um Speicherbereiche handelt, 
welche für AVR Module reserviert sind sollte dabei keine Rolle spielen.

Aber nachdem du mir nichtmal einen Ansatz einer sinnvollen Version 
spendieren konntest muss ich annehmen, dass du wohl der "Profi" bist.

Ich will hier ja keinen Prollo spielen ... aber nein, ich bin definitiv 
kein Anfänger mehr.

Angesichts der Menge an Antworten werde ich mich wohl mal an die 
Parameterübergabe von AVR GCC inline assembler machen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kjartan Ferstl schrieb:
> super danke (allgemeinbildung++)

++allgemeinbildung wäre sinvoller (erst erhöhen, dann den
erhöhten Wert benutzen), als den alten Stand zu nutzen.

Deshalb macht mich der Name C++ auch immer etwas misstrauisch.
++C fände ich vielversprechender.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde mal versuchen, die Quellvariablen, anstatt die Zielvariable zu 
shiften:

quick and dirty:
uint8_t *temp = Uuint8_t*) &ziel;

ziel[0] = var1;
ziel[1] = var2;
ziel[2] = var3;

Abgesehen davon, dass die Variante mit der Union trotzdem geht. Muss 
halt nur etwas nachdenken, und dann im Hauptprogramm im Beitrag von Tim 
die 255 u. 65535 durch var 1 bis 3 ersetzen.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ups, bitte streicht den ersten Satz in meinem letzten Post...

Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Kjartan Ferstl schrieb:
>> super danke (allgemeinbildung++)
>
> ++allgemeinbildung wäre sinvoller (erst erhöhen, dann den
> erhöhten Wert benutzen), als den alten Stand zu nutzen.
>
> Deshalb macht mich der Name C++ auch immer etwas misstrauisch.
> ++C fände ich vielversprechender.

unvorstellbar was hier für sinnvolle themenorientierte Antworten 
autauchen.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kjartan Ferstl schrieb:
> Nein, ich fragte ob es möglich ist, eine 8-byte Variable auf das 2. byte
> einer 32 bit Variablen zu schreiben.

Eine Variable mit 8 Byte auf ein Byte zu legen, geht nur mit
guter Kompression.

Aber davon abgesehen: was du m.E. wirklich willst, könnte so
aussehen:
    uint32_t   ziel;
#define var3 (((uint8_t*)&ziel)[0])
#define var2 (((uint8_t*)&ziel)[1])
#define var1 (((uint16_t*)&ziel)[1])
    ...
    var1 = 32000; // schreibt in die oberen 16 Bit von ziel
    var2 = 120;   // dto. 2. Byte von Ziel
    var3 = 120;   // dto. unterstes Byte von Ziel

Wahlweise int..._t statt uint..._t.

Die genannten Abhängigkeiten von Endianness etc. gelten
hierbei auch.

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kjartan Ferstl schrieb:
> unvorstellbar was hier für sinnvolle themenorientierte Antworten
> autauchen.

Ruhig, Brauner!

Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke

*Vermutung an Zeiger als vernünftigste Lösung hat sich damit wohl 
bestätigt

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So ähnlich wird übrigens gelegentlich die angebliche
globale Variable errno definiert
(etwa #define errno (*(_get_address_of_blabla())) mit einer
Funktion, die die Adresse liefert)

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachdem du nicht gesagt hast, in welcher Sprache du das
haben willst, könnte ich noch die FORTRAN-Anweisung EQUIVALENCE
in die Runde werfen, die macht genau das.

Aber das willst du wahrscheinlich auch nicht hören :-)

Autor: Kjartan Ferstl (kjartan)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Nachdem du nicht gesagt hast, in welcher Sprache du das
> haben willst,...
nur nie den ersten Post lesen
> ... Da ist mir C doch lieber ...

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, verloren

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> ok, verloren

Nö, da stand ja nur der Compilername (GNU Compiler Collection, aber
das ist ja ohnehin das Thema dieses Teilforums).  GCC kann auch
FORTRAN, also liegst du gar nicht so daneben. ;-)  Aber FORTRAN
bietet dafür noch andere Scheußlichkeiten, beispielsweise die
Benutzung von COMMON-Blöcken in zwei verschiedenen Modulen, die
dann in beiden verschieden definiert werden...  Das kann man übrigens
beim GCC auch in C haben, da nicht initialisierte globale Variablen
standardmäßig ebenfalls in COMMON-Blöcken untergebracht werden (kann
man aber abschalten mit -fno-common).  Das sieht dann ungefähr so
aus:

foo.c:
unsigned long myvar;

unsigned long
getmyvar(void)
{
        return myvar;
}

bar.c:
unsigned char myvar[4];

void
initmyvar(void)
{
        myvar[0] = 42;
        myvar[2] = 0x42;
}

main.c:
extern void initmyvar(void);
extern unsigned long getmyvar(void);

int
main(void)
{
        initmyvar();
        return (int)getmyvar();
}

Hier der disassemblierte Code des Compilats:
0000010e <main>:
 10e:   0e 94 96 00     call    0x12c   ; 0x12c <initmyvar>
 112:   0e 94 8d 00     call    0x11a   ; 0x11a <getmyvar>
 116:   cb 01           movw    r24, r22
 118:   08 95           ret

0000011a <getmyvar>:
 11a:   60 91 00 02     lds     r22, 0x0200
 11e:   70 91 01 02     lds     r23, 0x0201
 122:   80 91 02 02     lds     r24, 0x0202
 126:   90 91 03 02     lds     r25, 0x0203
 12a:   08 95           ret

0000012c <initmyvar>:
 12c:   8a e2           ldi     r24, 0x2A       ; 42
 12e:   80 93 00 02     sts     0x0200, r24
 132:   82 e4           ldi     r24, 0x42       ; 66
 134:   80 93 02 02     sts     0x0202, r24
 138:   08 95           ret

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch schrieb:
> Nö, da stand ja nur der Compilername (GNU Compiler Collection, aber
> das ist ja ohnehin das Thema dieses Teilforums).

Das hatte ich auch gelesen, aber ich traue mich nicht damit
zu argumentieren.
Schließlich hat er dann ja noch C erwähnt.
Außerdem bin ich mir nicht sicher, ob die Diskussion darüber
entspannt wäre.

> Das kann man übrigens beim GCC auch in C haben...
Stimmt.
Nur ist es in FORTRAN ausdrücklich so vorgesehen, wenn auch
dann nicht portabel.
Also eine explizit geduldete Schweinerei, während man in C nicht
darüber spricht.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Wachtler schrieb:
> Also eine explizit geduldete Schweinerei, während man in C nicht
> darüber spricht.

Da der Linker zwischen beiden aber der gleiche ist, ist auch klar,
dass beides auf genau gleiche Weise funktioniert. ;-)

Zugegeben aber, das ist und bleibt eine typische FORTRAN-Lösung,
während die typische C-Antwort darauf halt die union ist.  Die ist
auch nicht wirklich portabel, aber zumindest "portabel genug",
wenn man die durch endianess und alignment verursachten Probleme
im Blick behält.

Btw., diese COMMON-Block-Lösung ist auch in C eine der möglichen
zulässigen Implementierungsvarianten.  Da es historisch so gehandhabt
worden ist, lässt der Standard eine derartige Implementierung nach
wie vor als konform durchgehen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.