Zugriff auf einzelne Bytes in avrgcc

OP #2610583
Hi

Gibt es eine komfortable Möglichkeit auf einzelne Bytes in einem 
größerem Datentyp zuzugreifen?

Folgendes habe ich zuerst probiert (x ist als volatile uint32_t 
definiert, a als uint8_t).
1
x = (x & ~(uint32_t)0xFF) | a;

Hier wird jedoch das ganze Byte aus dem SRAM geladen wieder gespeichert.

Über Pointer (-Pfusch) funktioniert es, allerdings unschön, da es nur 
auf Littleendian-Systemen funktionieren würde:
1
uint8_t* ptr = &x;
2
*ptr = a;

Geht das schöner?
Gast
Samuel K. schrieb:
> Geht das schöner?

wenn du schreibst eine stuktur dann ist es erstmal egal ob Littleendian 
oder big. Denn eine Struktur ist nie irgendwie ausgerichtet. Und damit 
ist deine zeiger lösung schon ok

uint8t_t r = ((uint8_t*)&x)[0...x];

Wenn es um eine zahl geht, dann geht es so

uint8t_t r = (x>>x)&0xff;
OP
Andreas B. schrieb:
> Ich vermute, du meinst die ganzen 32 Bit von x.

Ja ich meinte die 32bit.

Andreas B. schrieb:
> Aber x ist volatile, da
> bleibt dem Compiler so oder so keine andere Wahl.

Das volatile muss leider bleiben, da der Wert in einem Interrupt 
gebraucht wird, allerdings ist der Interrupt diesem Zugriff sicher 
ausgeschaltet. Aber das lässt sich dem Compiler wohl nicht mitteilen.

Johann L. schrieb:
> Das hat alles nix mit avr-gcc zu tun.
> Du kannst alles machen, was auch in C geht.
> Was in C nicht geht, geht auch mit avr-gcc nicht.

Naja, avrgcc bietet schon ein paar Funktionen, die z.B. auf einem PC 
recht sinnfrei wären. Und das Problem hier ist auch ziemlich spezifisch, 
da der Avr als 8-bit µC viele Instruktionen braucht, um irgendetwas mit 
einem uint32_t zu machen.

Ganz sauber finde ich die Pointerlösung nicht, aber wenn es nichts 
besseres gibt...
Gast
Hallo Samuel

Ich denke, dein avrgcc versteht auch folgende Anweisungen:
1
uint32_t Value = 0xAABBCCDD;
2
uint8_t Byte1;
3

4
Byte1 = (uint8_t)((Value >> 8) & 0x000000FF);

Beste Grüsse

Geri
Samuel K. schrieb:
> Das volatile muss leider bleiben, da der Wert in einem Interrupt
> gebraucht wird, allerdings ist der Interrupt diesem Zugriff sicher
> ausgeschaltet. Aber das lässt sich dem Compiler wohl nicht mitteilen.

Doch, man kann einen Zeiger auf die Variable auf einen Zeiger ohne 
volatile casten. Oder umgekehrt die Variable nur nach volatile casten 
wenn nötig. Oder statt volatile ein memory barrier Makro verwenden.

Ich hab es mal mit einem avr-gcc 4.5.3 ausprobiert und der würde 
trotzdem die ganzen 32 Bit laden. Bei der Und-Verknüpfung erkennt er, 
dass die 0xff Bytes keinen Einfluss haben, aber beim erweiterten uint8_t 
erkennt er nicht, dass alle oberen Bytes gleich 0 sind und führt alle 4 
or-Instruktionen aus.
Persönliche Seite
Samuel K. schrieb:
> Johann L. schrieb:

>> Das hat alles nix mit avr-gcc zu tun.
>> Du kannst alles machen, was auch in C geht.
>> Was in C nicht geht, geht auch mit avr-gcc nicht.
>
> Naja, avrgcc bietet schon ein paar Funktionen, die z.B. auf einem PC
> recht sinnfrei wären. Und das Problem hier ist auch ziemlich spezifisch,
> da der Avr als 8-bit µC viele Instruktionen braucht, um irgendetwas mit
> einem uint32_t zu machen.

So ist das eben, wenn man 32-Bit Arithmetik auf einem 8-Bit auf einem 
8-Bit µC macht.

Und wenn das Ding volatile ist, muss es komplett geladen werden. Alles 
andere wäre ein Compilerbug.

> Ganz sauber finde ich die Pointerlösung nicht, aber wenn es nichts
> besseres gibt...

Das Thema wurde schon 100* durchgekaut.

Neben der fehlenden Portirebarkeit und Hack durch verkorksen der 
Poointer, ist ein weiteres Probleme die Verletzung der Aliasing-Regeln 
von C.

Wozu wird der Hack überhapt gebraucht?

Reine Kosmethik im erzeugten Code?
Oder gibt's wirklich ein Performance-Problem?
Persönliche Seite
Dürfte in die Richtung gehen von

http://gcc.gnu.org/PR27663
http://gcc.gnu.org/PR41076
1
#include <stdint.h>
2

3
uint32_t volatile x;
4

5
void insert_0 (uint8_t a)
6
{
7
    x = (x & ~0xFFUL) | a;
8
}
Mit aktuellem avr-gcc -S -Os übersetzt wird das zu
1
insert_0:
2
  lds r20,x
3
  lds r21,x+1
4
  lds r22,x+2
5
  lds r23,x+3
6
  clr r20
7
  or r20,r24
8
  sts x,r20
9
  sts x+1,r21
10
  sts x+2,r22
11
  sts x+3,r23
12
  ret
Hat 1 überflüssige Instruktion die noch optimierbar wäre.

Das "clr" ist ein 32-Bit AND und das "or" ein 8-Bit OR.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 14 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.