Auf ein Byte zugreifen

Gast #1670748
Lesenswert?

Hallo,
Ich sammle so meine ersten Programmiererfahrungen mit dem ATtiny25 und 
AVRStudio4.
es geht mir um die Frage, wie ich auf ein einzelnes der 4 Byte einer 
unsigned long int variable zugreifen kann.
1
unsigned long int my_ul32;
2
unsigned char my_byte;
3

4
my_byte = my_ul32;        // lies byte_0
5
my_byte = my_ul32 >> 8;   // lies byte_1
6
my_byte = my_ul32 >> 16;  // lies byte_2
7
my_byte = my_ul32 >> 24;  // lies byte_3
8

9
my_ul32 = (my_ul32 & 0xFFFFFF00) | my_byte;       // schreib an position 0
10
my_ul32 = (my_ul32 & 0xFFFF00FF) | my_byte << 8;  // schreib an position 1
11
my_ul32 = (my_ul32 & 0xFF00FFFF) | my_byte << 16; // schreib an position 2
12
my_ul32 = (my_ul32 & 0x00FFFFFF) | my_byte << 24; // schreib an position 3
Ich weiss jetzt nicht ob der GCC (AVRWIN) meine Absicht durchschaut und 
das obtimieren kann, oder ob der jetzt beigeht und tatsächlich 24 mal 
schieben läßt.
#1670758
Lesenswert?

Oktoberfestbesucher schrieb:
> Hallo,
> Ich sammle so meine ersten Programmiererfahrungen mit dem ATtiny25 und
> AVRStudio4.
> es geht mir um die Frage, wie ich auf ein einzelnes der 4 Byte einer
> unsigned long int variable zugreifen kann.
> ...

Dazu gibt es mehrere Varianten (je nach persönlicher Vorliebe)
hier schon etliche Threads:
- Adresse der Variable in eine uint8_t* casten und darüber mit
  einem Index auf dei Byte zugreifen (mein Favorit)
- Mit einer union (Liebling der meisten anderen)
- Shiften so wie du es machst (portabel, aber ansonsten
  uneffizient und unschön m.E.)
- ...

> Ich weiss jetzt nicht ob der GCC (AVRWIN) meine Absicht durchschaut und
> das obtimieren kann, oder ob der jetzt beigeht und tatsächlich 24 mal
> schieben läßt.

Ich fürchte nein; genaueres sieht man am erzeugten Code.
Gast #1670760
Lesenswert?

Hi,

ich denke, eine Union wäre geschickter, meinst du nicht?
1
union {
2
unsigned long LongVar;
3
unsigned char ChArr[4];
4
} stLong;

Zugriff auf die einzelnen Bytes dann mit VarName.ChArr[x]. Keine Gewähr 
für den Code, nur beispielhaft ;)

Ralf
#1671761
Lesenswert?

Jo, genau so meinte ich das.

(Danke, habe in der Zwischenzeit nett gegrillt und ein leckeres 
Rauchbier getrunken...)

Wobei es auch ohne Zeigervariable geht; nicht unbedingt besser oder 
übersichtlicher, aber geiziger:
1
  uint32_t Value;
2

3
  for( i = 0; i < sizeof( Value ); ++i )
4
    output( ((uint8_t*)&Value)[i] );
Gast #1672938
Lesenswert?

Karl heinz Buchegger schrieb:
> output( pHelp[i] );

Danke für die Antwort.
Das man einem Pointer auch einen Index dranhängen kann, hab ich bisher 
nicht gewußt.
Muß ich testen! Besten Dank



und  Klaus Wachtler (mfgkw) schrieb:
> output( ((uint8_t*)&Value)[i] );

Danke für die Antwort, sieht gut aus. Ich versteh es noch nicht ganz 
100%,
werde es aber testen.
Frage dazu: wie würde denn umgekehrt input gehen?
#1672952
Lesenswert?

Mit dem output hatte ich ja nur die Version von KHB aufgegriffen.

Original hast du ja direkte Zuweisungen.
Das würde etwa so aussehen:
1
    // eine Richtung:
2
    mybyte_mostsignificant = ((uint8_t*)&Value)[3];
3
    mybyte3                = ((uint8_t*)&Value)[2];
4
    mybyte2                = ((uint8_t*)&Value)[1];
5
    mybyteleastsignificant = ((uint8_t*)&Value)[0];
6

7
    // andere Richtung:
8
    ((uint8_t*)&Value)[3] = mybyte_mostsignificant;
9
    ((uint8_t*)&Value)[2] = mybyte3;
10
    ((uint8_t*)&Value)[1] = mybyte2;
11
    ((uint8_t*)&Value)[0] = mybyteleastsignificant;

"most" und least" bezieht sich auf einen Rechner mit Little 
Endian-Architektur, bei einem BE-System müsste man die Bytes andersrum 
interpretieren.
#1672963
Lesenswert?

Oktoberfestbesucher schrieb:
> Ich versteh es noch nicht ganz 100%,

&Value liefert dir die Adresse deiner Variable value (von der
ich ausgehen, daß sie 32 Bit groß ist).

(uint8_t*)&Value ist immer noch dieselbe Adresse, allerdings
zu interpretieren als Zeiger auf uint8_t, also Zeiger auf Byte.
Das könnte jetzt ein Zeiger auf ein Byte sein, oder auf das erste
eines ganzen Felds von Byte.
(Siehe C-Buch: Analogie zwischen Zeigern und Feldern...)

Mit ((uint8_t*)&Value)[0] etc. nimmt man jetzt das
soundsovielte Element des vermeintlichen Feldes, als das
soundsovielte Byte von Value.
Solange man im Bereich [0] bis [3] bleibt, greift man damit
auf die entsprechenden Byte von Value zu.

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