Forum: Mikrocontroller und Digitale Elektronik Auf ein Byte zugreifen


von Oktoberfestbesucher (Gast)


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.

von Klaus W. (mfgkw)


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.

von Ralf (Gast)


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

von Oktoberfestbesucher (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> - Adresse der Variable in eine uint8_t* casten und darüber mit
>   einem Index auf dei Byte zugreifen (mein Favorit)

kannst du mal einen Code-Schnipsel dazu posten,
ich kriegs nicht gecastet

von Karl H. (kbuchegg)


Lesenswert?

1
  uint32_t Value;
2
  uint8_t* pHelp;
3
4
  // mach was mit allen Bytes von Value
5
  pHelp = (uint8_t*) &Value;
6
  for( i = 0; i < sizeof( Value ); ++i )
7
    output( pHelp[i] );

von Klaus W. (mfgkw)


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] );

von Oktoberfestbesucher (Gast)


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?

von Klaus W. (mfgkw)


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.

von Klaus W. (mfgkw)


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.

von Oktoberfestbesucher (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Solange man im Bereich [0] bis [3] bleibt, greift man damit
> auf die entsprechenden Byte von Value zu.

Sahneschnitten_toll!

Besten Dank!

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.