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


von Kjartan F. (kjartan)


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:
1
ziel|var1;
2
ziel<<=8;
3
ziel|=var2;
4
ziel<<=8;
5
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

von Meinereiner (Gast)


Lesenswert?

union

von Kjartan F. (kjartan)


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?

von Tim T. (tim_taylor) Benutzerseite


Lesenswert?

Doch, sollte gehen:
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
union {
5
 unsigned int ziel;
6
 struct {
7
  unsigned char var3;
8
  unsigned char var2;
9
  unsigned short var1;
10
 } quelle;
11
} daten;
12
13
int main(void) {
14
 daten.quelle.var3=255;
15
 daten.quelle.var2=255;
16
 daten.quelle.var1=65535;
17
 printf("%u\n", daten.ziel);
18
 system("PAUSE");  
19
 return 0;
20
}
Ausgabe ist dann 4294967295.

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

von Kjartan F. (kjartan)


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?

von gsdfgsd (Gast)


Lesenswert?

Sind die Register verstreut? Gib mal Detailinformationen, was wo liegt

von Bernhard R. (barnyhh)


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

von Kjartan F. (kjartan)


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.

von Klaus W. (mfgkw)


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.

von Klaus (Gast)


Lesenswert?

Ich würde mal versuchen, die Quellvariablen, anstatt die Zielvariable zu 
shiften:

quick and dirty:
1
uint8_t *temp = Uuint8_t*) &ziel;
2
3
ziel[0] = var1;
4
ziel[1] = var2;
5
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.

von Klaus (Gast)


Lesenswert?

ups, bitte streicht den ersten Satz in meinem letzten Post...

von Kjartan F. (kjartan)


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.

von Klaus W. (mfgkw)


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:
1
    uint32_t   ziel;
2
#define var3 (((uint8_t*)&ziel)[0])
3
#define var2 (((uint8_t*)&ziel)[1])
4
#define var1 (((uint16_t*)&ziel)[1])
5
    ...
6
    var1 = 32000; // schreibt in die oberen 16 Bit von ziel
7
    var2 = 120;   // dto. 2. Byte von Ziel
8
    var3 = 120;   // dto. unterstes Byte von Ziel

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

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

von Klaus W. (mfgkw)


Lesenswert?

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

Ruhig, Brauner!

von Kjartan F. (kjartan)


Lesenswert?

Danke

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

von Klaus W. (mfgkw)


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)

von Klaus W. (mfgkw)


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 :-)

von Kjartan F. (kjartan)


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 ...

von Klaus W. (mfgkw)


Lesenswert?

ok, verloren

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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:
1
unsigned long myvar;
2
3
unsigned long
4
getmyvar(void)
5
{
6
        return myvar;
7
}

bar.c:
1
unsigned char myvar[4];
2
3
void
4
initmyvar(void)
5
{
6
        myvar[0] = 42;
7
        myvar[2] = 0x42;
8
}

main.c:
1
extern void initmyvar(void);
2
extern unsigned long getmyvar(void);
3
4
int
5
main(void)
6
{
7
        initmyvar();
8
        return (int)getmyvar();
9
}

Hier der disassemblierte Code des Compilats:
1
0000010e <main>:
2
 10e:   0e 94 96 00     call    0x12c   ; 0x12c <initmyvar>
3
 112:   0e 94 8d 00     call    0x11a   ; 0x11a <getmyvar>
4
 116:   cb 01           movw    r24, r22
5
 118:   08 95           ret
6
7
0000011a <getmyvar>:
8
 11a:   60 91 00 02     lds     r22, 0x0200
9
 11e:   70 91 01 02     lds     r23, 0x0201
10
 122:   80 91 02 02     lds     r24, 0x0202
11
 126:   90 91 03 02     lds     r25, 0x0203
12
 12a:   08 95           ret
13
14
0000012c <initmyvar>:
15
 12c:   8a e2           ldi     r24, 0x2A       ; 42
16
 12e:   80 93 00 02     sts     0x0200, r24
17
 132:   82 e4           ldi     r24, 0x42       ; 66
18
 134:   80 93 02 02     sts     0x0202, r24
19
 138:   08 95           ret

von Klaus W. (mfgkw)


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.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

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
Noch kein Account? Hier anmelden.