Mikrocontroller: Probleme mit char Buffer

Gast #4825216
Guten Morgen,

auf einem Mikrocontroller soll ein Empfangspuffer vom Typ char in 
entsprechende Variablen kopiert werden.
1
uint8_t TestPuffer[256]
2

3
uint16_t Length;
4
uint32_t IpAddr;
5
uint8_t *Data;

In den ersten beiden char Elementen befindet sich die Länge in den 
nächsten 4 Elementen eine Ip Addresse. Die Daten befinden sich ab dem 
Element 6.

WIe kann man die Daten am Besten in die entsprechenden Variablen 
kopieren?
Gast #4825228
Es ist erstmal wichtig zu wissen, in welcher Form die ersten Daten 
vorliegen. Sind das einfach in 8Bit Stükchen zerteilte 16 bzw 32Bit 
Integer oder sind diese anders kodiert?
Gast #4825263
zoe schrieb:
> Mit memcpy könnte man sowas machen. Gibt es da eine bessere
> Alternative?

Was spricht gegen memcpy?

Alternativ könntest du dir natürlich eine Union aus einer Struktur mit 
den Daten drin und dem Buffer deklarieren. Bei den Unions bin ich mir 
nicht zu 100% sicher, ob jeder Compiler die Elemente des Struct im 
Buffer gleich anodnen muss.

Oder du machst das mit Pointern. Also immer auf den Typ casten und dann 
den offset addieren oder so.

Der Aufwand für den µC dürfte aber immer relativ gleich sein.

Ich persönlich würde die memcpy oder pointer Variante nehmen.
Gast #4826193
zoe schrieb:
> In den ersten beiden char Elementen befindet sich die Länge in den
> nächsten 4 Elementen eine Ip Addresse. Die Daten befinden sich ab dem
> Element 6.
>
> WIe kann man die Daten am Besten in die entsprechenden Variablen
> kopieren?

Sowas regt mich auf. Wie - bittesehr - stehen Länge un IP-Adresse denn 
dort drin? Bigendian oder Littleendian? Du müßtest sowas schon 
dazusagen.

Ansonsten ist sowas doch kinderleicht - sofern ich dich wenigstens 
halbwegs verstanden habe:
long L;
 L = Testpuffer[0];
 L = (L << 8) | Testpuffer[1];
 Laenge = L;

Und sinngemäß dasselbe für die IP-Adr. Du solltest es aber für deine 
Endianess anpassen - gelle?

W.S.
Gast #4826357
typedef struct {
   uint16_t Length;
   uint32_t IpAddr;
   uint8_t TestPuffer[256]
} __attribute__((packed)) uart_t;

uart_t uart;



Pointer auf das erste Element
uint8_t *buffer_ptr = (unsigned char*) &uart
Gast #4826366
an den Pointer buffer_ptr werden die Daten dann linear reinkopiert.

Anschließend kannst du mit
uart.Length
uart.IpAddr oder
uart.TestPuffer

auf die Daten zugreifen
Gast #4826650
Hallo,

müsste auch so gehen:
1
typedef struct {
2
   uint16_t Length;
3
   uint32_t IpAddr;
4
   uint8_t Data[250];
5
} message_t;
6

7
......
8

9
message_t *message = (message_t *) TestPuffer;
10
uint32_t ip = message->IpAddr;
11

12
......

ms
Gast #4826659
Sobald man portabel programmieren möchte holt man sich die Bytes einzeln 
raus, shiftet diese passend und odert sie zum Gesamtwert.
Alle diese Unions um Memcpys führen irgendwann zu Problemen.
#4826687
Mampf F. schrieb:
> E-Techniker schrieb:
>> __attribute__((packed))
>
> Auf 8Bit AVRs vermutlich nicht mal notwendig, schaden tut es aber
> niemals!

Doch.

> Vlt möchte man den Code irgendwann auf einen ARM portieren, dann hätte man
> da ein Problem ohne packed (padding)

Und ggf. mit auch, denn nicht jeder ARM unterstützt überhaupt Zugriffe 
mit falschem Alignment.
#4826708
ms schrieb:
> müsste auch so gehen:
>
> typedef struct {
>    uint16_t Length;
>    uint32_t IpAddr;
>    uint8_t Data[250];
> } message_t;
>
> ......
>
> message_t *message = (message_t *) TestPuffer;
> uint32_t ip = message->IpAddr;

aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht
Gast #4826998
PittyJ schrieb:
> Sobald man portabel programmieren möchte holt man sich die Bytes einzeln
> raus, shiftet diese passend und odert sie zum Gesamtwert.

Ja, eben! Damit hast du als so ziemlich einziger in dieser ganzen Runde 
den Nagel auf den Kopf getroffen - aber es hört dir keiner zu.

Stattdessen wird ganz gewiß ab hier noch ellenlang über weitere structs 
und unions schwadroniert werden.

W.S.
#4827337
ms schrieb:
> Walter S. schrieb:
>> aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht
>
> ja muss ich dir recht geben. Sobald man das Gesamtsystem (Programm)
> nicht im griff hat ist der misserfolg vorprogrammiert.

Man kann solche Hinweise auch mal ernst nehmen...
(Aber eigentlich soll dem TO geholfen werden.)

Mir fallen dazu ein:
- Alignment nicht beachtet (zusätzliche Füllbytes, welche im char-Buffer 
nicht sind)
- Wenn message an einer ungünstigen Adresse liegt (weil ja ein 
char-Buffer das darf) geht bei verschiedenen Umgebungen der Zugriff auf 
32bit schief message->IpAddr
Gast #4827435
Mampf F. schrieb:
> Rolf M. schrieb:
>> Doch.
>
> Erklärung?

Hab ich doch im Anschluss geschrieben.

> Wofür bräuchte ein 8Bit-Controller Padding in einem Struct?

Vielleicht hab ich dich missverstanden. Ich dachte mit "niemals" 
meintest du "auf keinem µC in keiner Situation". Wenn die Aussage aber 
auf den AVR beschränkt zu verstehen ist, dann ist das was anderes.
Gast #4827904
Hallo Steffen,

Steffen R. schrieb:
> - Alignment nicht beachtet (zusätzliche Füllbytes, welche im char-Buffer
> nicht sind)
> - Wenn message an einer ungünstigen Adresse liegt (weil ja ein
> char-Buffer das darf) geht bei verschiedenen Umgebungen der Zugriff auf
> 32bit schief message->IpAddr

kannst Du mir da mal ein Beispiel geben.Ich würde das gerne mal bei mir 
im Labor Testen lassen an verschieden DEV-Systemen.

ms
#4829839
ms schrieb:
> Hallo Steffen,
>
> Steffen R. schrieb:
>> - Alignment nicht beachtet (zusätzliche Füllbytes, welche im char-Buffer
>> nicht sind)
>> - Wenn message an einer ungünstigen Adresse liegt (weil ja ein
>> char-Buffer das darf) geht bei verschiedenen Umgebungen der Zugriff auf
>> 32bit schief message->IpAddr
>
> kannst Du mir da mal ein Beispiel geben.Ich würde das gerne mal bei mir
> im Labor Testen lassen an verschieden DEV-Systemen.

Der erste Punkt ist einfach. Man nehme ein System mit Alignment 4 oder 8 
(z.B. arm-gcc)

Es entsteht
1
typedef struct {
2
   uint16_t Length;
3
-- 2 Füllbytes --
4
   uint32_t IpAddr;
5
   uint8_t Data[250];
6
} message_t;

Für den zweiten Fall habe ich kein Beispiel zu Hand. Das char Array 
erfordert ein Alignment von 1 und kann somit z.B. auch an ungeraden 
Adressen anfangen. Häufig beginnen die Linker aber an eine ihrem max. 
Alignment passenden Stelle. Daher wird es in vielen Fällen nicht 
crashen, solange man die Struktur genau an den Anfang des Arrays legt.

Nur für die, die nicht kennen, dass man manche Zugriffe nicht auf 
beliebige Adressen durchführen darf:

Z.B. beim C166 würde ein modifiziertes Beispiel crashen:
1
message_t *message = (message_t *) &TestPuffer[1];
2
uint32_t ip = message->IpAddr
#4830590
ms schrieb:
> Walter S. schrieb:
>> aber nur mit etwas Glück, bei Pechvögeln funktioniert das nicht
>
> ja muss ich dir recht geben. Sobald man das Gesamtsystem (Programm)
> nicht im griff hat ist der misserfolg vorprogrammiert.
>
> ms

ich meinte damit was anderes, nämlich dass das nur funktioniert wenn die 
Bytes des 16 bzw. 32-Bit Wortes in der passenden Reihenfolge abgelegt 
sind,
Stichwort: Endianess

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 9 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.