Forum: Mikrocontroller und Digitale Elektronik Mikrocontroller: Probleme mit char Buffer


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von zoe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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?

von Baendiger (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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?

von zoe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Es handelt sich hierbei um 8bit, 16bit und auch 32bit Stücke.

von zoe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Mit memcpy könnte man sowas machen. Gibt es da eine bessere Alternative?

von Hmmhmm (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Peter D. (peda)


Bewertung
0 lesenswert
nicht lesenswert
zoe schrieb:
> uint8_t *Data;

Das ist nur ein Zeiger, da kannst Du nichts reinkopieren.
Es muß heißen:
1
uint8_t Data[250};

Wenn die Elemente zusammen hängen, mach ne Struct daraus.

von Walter S. (avatar)


Bewertung
0 lesenswert
nicht lesenswert
zoe schrieb:
> uint8_t *Data;

da kannst du nicht die Daten selbst reinkopieren, das ist nur ein 
Zeiger.
Je nachdem was du willst brauchst du vielleicht
Data = &TestPuffer[6];

von W.S. (Gast)


Bewertung
1 lesenswert
nicht lesenswert
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.

von zoe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für die Hilfe.

Wie würde sowas mit union funktionieren?

von Jim M. (turboj)


Bewertung
-1 lesenswert
nicht lesenswert
zoe schrieb:
> Wie würde sowas mit union funktionieren

Vermutlich gar nicht.

von E-Techniker (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
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

von E-Techniker (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
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

von zoe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Die eingehenden Daten liegen im TestPuffer. Der Puffer liegt somit nicht 
in der Struktur.

von zoe (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Wie mappt man nun die obige Struktur auf den TestPuffer?

von Dirk B. (dirkb2)


Bewertung
0 lesenswert
nicht lesenswert
zoe schrieb:
> Wie mappt man nun die obige Struktur auf den TestPuffer?

Indem man der Leseroutine den Anfang der struct übergibt und somit 
gleich in die struct liest.

von Walter S. (avatar)


Bewertung
0 lesenswert
nicht lesenswert
E-Techniker schrieb:
> 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

und die Endianess wird schon passen?

von ms (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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

von PittyJ (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Mampf F. (mampf) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
E-Techniker schrieb:
> __attribute__((packed))

Auf 8Bit AVRs vermutlich nicht mal notwendig, schaden tut es aber 
niemals! Vlt möchte man den Code irgendwann auf einen ARM portieren, 
dann hätte man da ein Problem ohne packed (padding)

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Walter S. (avatar)


Bewertung
0 lesenswert
nicht lesenswert
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

von ms (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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

von W.S. (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Mampf F. (mampf) Benutzerseite


Bewertung
0 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Doch.

Erklärung?

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

Hmm ... Obwohl, wenn da ein 16Bit und 32Bit Wort noch im Struct ist, 
wäre die Adressierung vmtl einfacher, wenn gepaddet wird ...

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Bewertung
0 lesenswert
nicht lesenswert
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

von Rolf Magnus (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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.

von ms (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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

von Arduino Fanboy D. (ufuf)


Bewertung
0 lesenswert
nicht lesenswert
ms schrieb:
> kannst Du mir da mal ein Beispiel geben.

Erzeuge lustige Strukturen.
Lasse dir mit sizeof() die jeweilige Größe zeigen.
Daraus solltest du auf die Anzahl Füllbytes schließen können.

: Bearbeitet durch User
von Steffen R. (steffen_rose)


Bewertung
0 lesenswert
nicht lesenswert
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

von Walter S. (avatar)


Bewertung
1 lesenswert
nicht lesenswert
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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.