Hallo Leute,
ich nutze einen ATMEGA und wollte nur mal eure Meinung zu Folgendem
hören.
Kann ich davon ausgehen, dass
1
unsignedcharb[128];
2
unsignedlongk=123456;
3
4
*(b++)=k>>24;
5
*(b++)=k>>16;
6
*(b++)=k>>8;
7
*b=k;
und
1
*((unsignedlong*)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
1
k=*((unsignedlong*)b);
anstatt
1
k=((unsignedlong)*(b++))<<24;
2
k|=((unsignedlong)*(b++))<<16;
3
k|=((unsignedlong)*(b++))<<8;
4
k|=(unsignedlong)*(b++);
gelten.
Sehe ich das richtig?
Vielen Dank im Voraus...
@ 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?
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
> 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
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
1
*((unsignedlong*)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.
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
@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.
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
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
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...
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.