mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik long in byte-Array ablegen


Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

ich nutze einen ATMEGA und wollte nur mal eure Meinung zu Folgendem 
hören.
Kann ich davon ausgehen, dass
  unsigned char b[128];
  unsigned long k = 123456;

  *(b++) = k>>24;
  *(b++) = k>>16;
  *(b++) = k>>8;
  *b = k;
und
  *((unsigned long*)b) = k;
bei diesen Controllern das Gleiche bewirken?
Der zweite Code wäre dann ja um einiges schneller und besser.
Umgekehrt würde um k wieder zu kriegen dann ja auch
  k=*((unsigned long*)b);
anstatt
  k = ((unsigned long) *(b++))<<24;
  k |= ((unsigned long) *(b++))<<16;
  k |= ((unsigned long) *(b++))<<8;
  k |= (unsigned long) *(b++);
gelten.
Sehe ich das richtig?

Vielen Dank im Voraus...

Autor: Gerhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

wie wärs mit:

union CHG{
      unsigned char c[4];
      unsigned long k;
};

union CHG chg;
unsigned char b[128];
int i;

chg.k = 123456;

b[i++] = k[0];
b[i++] = k[1];
b[i++] = k[2];
b[i++] = k[3];

Gerhard

Autor: Gerhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sorry, muss natürlich so heissen:


union CHG{
      unsigned char c[4];
      unsigned long k;
};

union CHG chg;
unsigned char b[128];
int i;

chg.k = 123456;

b[i++] = c[0];
b[i++] = c[1];
b[i++] = c[2];
b[i++] = c[3];

Gerhard

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Gerhard
das das möglich ist, sehe ich ein.
Sollte aber
*( (unsigned long*)b ) = k;
nicht auch das Gleiche bewirken, ohne viel Code schreiben zu müssen?

Autor: Gerhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das, sollte mit cast funktionieren:

unsigned char b[128];
unsigned long k = 123456;

  *(b++) = (unsigned char)k;
  *(b++) = (unsigned char)k>>8;
  *(b++) = (unsigned char)k>>16;
  *b = (unsigned char)k>>24;

Dabei nimmt der Compiler immer das lowbyte und schreibts in das Array.

aber
*( (unsigned long*)b ) = k;
was ist das ?
b ist ein char-array.
Schreib doch deinen Code mal in einen C-Compiler und schau wa der draus 
macht.

wieso kein long-array definieren ?

unsigned long b[128];
  unsigned long k = 123456;

  b[i++] = k;

gerhard

Autor: Roland Praml (pram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich denk mal, selbst wenn man es mit Bitshifts macht, dass das der 
Compiler schon checkt und entsprechend optimiert.

evtl geht auch memcpy(&b[i],&k,4)

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gast wrote:

> Kann ich davon ausgehen, dass
>
  unsigned char b[128];
>   unsigned long k = 123456;
> 
>   *(b++) = k>>24;
>   *(b++) = k>>16;
>   *(b++) = k>>8;
>   *b = k;
> und
>
  *((unsigned long*)b) = k;
> bei diesen Controllern das Gleiche bewirken?

Nö.

Im oberen Code speicherst Du das höchstwertige Byte immer zuerst.

Im unteren Code ist es compilerabhängig, was zuerst gespeichert wird.


Wenn es darum geht, Daten byteweise zu übertragen, nehme ich 
grundsätzlich die compilerunabhängige Version, auch wenns minimal länger 
dauert.

Wenns aber nur im EEPROM gespeichert und wieder ausgelesen werden soll, 
dann isses wurscht.


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die vielen Antworten bis jetzt!

@Gerhard
>aber
>*( (unsigned long*)b ) = k;
>was ist das ?
>b ist ein char-array.
Stimmt nicht ganz. b ist Pointer auf den Anfang eines char-Arrays, er 
zeigt also auf das erste Byte des Arrays. Da es ein "unsigned 
char*"-Pointer ist, zeigt er immer nur auf ein Byte. Durch den Cast nach 
(unsigned long*) entsteht ein Pointer mit der Adresse von b, der aber 
auf den Anfang eines 4-Byte-Langworts zeigt. Die äußere Klammer "*(...)" 
bedeutet dann: Schreibe in das Langwort auf das der Pointer zeigt den 
Wert von k.
Der Compiler schluckt das ohne Probleme.

@Roland Praml
>ich denk mal, selbst wenn man es mit Bitshifts macht, dass das der
>Compiler schon checkt und entsprechend optimiert.
Habs mit beidem versucht und mir den Assembler-Code angeschaut. Der 
AVR-GCC-Code ist mit den Shifts länger und langsamer. Da ich die Shifts 
an mehreren Stellen brauche, macht das schon einiges aus.

@Peter Dannegger
>Im unteren Code ist es compilerabhängig, was zuerst gespeichert wird.
Sorry, klar. Ich nutze den AVR-GCC-Compiler, der soweit ich weiß im 
Little Endian-Format speichert. Der Code ist für Speicher (z.B. 
Speicherkarten) gedacht, der nur in Sektoren adressierbar ist, sodass 
immer nur komplette Blöcke abgespeichert werden können. Ich suche dafür 
nach Möglichkeiten Variablen möglichst effizient und schnell ablegen zu 
können. Um die "Byteordnung" mache ich mir also nicht so viele Gedanken. 
Es ging mir vielmehr darum ob man sowas wie
*((unsigned long*)b) = k;
 immer so ohne weiteres machen darf, oder ob ich etwas was übersehen 
habe.

Wenn also alle Architekturen die ich verwende "Little Endian" sprechen, 
wäre der Code mit den Pointer-Casts vorzuziehen und kann bedenkenlose 
verwendet werden???

Vielen Dank, liebe Leute.

Autor: T.Stütz (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
kleiner Nachtrag @Gast

>Wenn also alle Architekturen die ich verwende "Little Endian" sprechen,
>wäre der Code mit den Pointer-Casts vorzuziehen und kann bedenkenlose
>verwendet werden???

Es gibt Architekturen (Prozessoren) die nehmen es einem sehr übel
wenn mann an eine ungerade Adresse mit Wort/Doppelwort Zugriffen 
hinlangt. Bsp C167.

Bei einer Variablen "unsigned char ucZeichen;" istaber nicht immer 
gewährleistet das selbige an einer geraden Adresse ist.

mfG
T.Stütz

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@T.Stütz
Stimmt, daran habe ich nicht gedacht. Weiß jemand den wie das bei den 
ATMEGAs ist?
Denn dann habe ich jetzt aber ein Problem! Ich würde ja prinzipiell auch 
mit den Shifts arbeiten, muss aber z.B. auch Floats in den Speichern 
ablegen. Da darf ich aber keine Shifts machen (Compiler: "invalid 
operands to binary >>"). Da ein Float 4 Byte hat müsste ich ihn erst 
z.B. per "(long*)" in etwas casten, was ich shiften darf, das per Shift 
in das Byte-Array ablegen und dann nach dem Auslesen wieder auf "float*" 
zurückcasten. Ob das so gut ist???

Wie wärs den tatsächlich mit "memcpy"? Da hätte ich zwar auch keinen 
Einfluss auf die "Byteorder", das Problem mit den ungeraden Adressen 
hätte sich aber dann erledigt.

Autor: Willi Wacker (williwacker)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal was anderes:

Abgesehen davon ob es "tut" (Little oder Big Endian oder was auch 
immer), es ist auch eine Stilfrage. Meiner Meinung nach sollte der Code 
so programmiert sein, dass er selbsterklärend ist und man damit auch 
möglichst ohne Kommentare auskommt.

Die Variante mit der Union würde dem entsprechen.

Die andere Variante, in die 4 Byte heute 4 chars, morgen 2 Integers und 
übermorgen ein Long reinzuschreiben, nicht! Ein solcher Code ist erst 
einmal verwirrend und MUSS kommentiert werden.

Eleganter ist das auch nicht, ein guter Compiler bekommt die 
union-Variante mit gleichem Byte-Aufwand hin. Selbst wenn nicht, die 
Übersicht hat gewonnen, damit ist der Code leichter zu pflegen und damit 
sinkt der spätere Aufwand für die Pflege. Bereits bei der Programmierung 
sollte man daran denken.

Bevor Ihr mich jetzt steinigt, einfach mal so meine Meinung nach der ich 
seit etlichen Jahren in allen möglichen Sprachen arbeite.

Nicht immer erfolgreich, wie ich zugeben muss. Code so zu schreiben ist 
nicht einfach. So wie ich finde, dass das Kommentieren eines Codes 
schwieriger ist, als die eigentliche Programmiererei.

Schöne Pfingsten

Willi Wacker

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Willi Wacker wrote:
> Meiner Meinung nach sollte der Code
> so programmiert sein, dass er selbsterklärend ist und man damit auch
> möglichst ohne Kommentare auskommt.


Also für "Selbsterklärung" kann ich mir nun aber überhaupt nichts 
kaufen.

Was nützt mir die schönste Erklärung, wenn sie falsch ist !


Ich bevorzuge daher immer die weniger Fehler provozierende Variante.

Wenn sie weniger "schön" ist, kann man sie ja in ein Macro verpacken.

Wenn ich also vermeiden kann, mir die Edianes des Compilers ansehen zu 
müssen, dann mach ich das auch.


Peter

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich habs jetzt jeweils mit
memcpy(b,&k,4);
gemacht. Das Ergebis ist bisher das Gleiche wie bei der Pointer-Variante 
(sogar die Codegröße ist gleich ;-) ) nur das ich somit hoffentlich die 
eventuellen Schwierigkeiten mit gerader/ungerader Adresse umgangen habe.
Bis jetzt läufts mal...

Autor: Gast (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nachtrag @Peter Dannegger
>Wenn ich also vermeiden kann, mir die Edianes des Compilers ansehen zu
>müssen, dann mach ich das auch.
Verstehe ich vollkommen! Nur brauche ich leider auch Floats und da darf 
ich kein Shift machen.

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.