Ich habe hier in einem Programm auf einem attyni2313 den Bedarf eines
Flagbytes und einer 16-bit globalen Variablen. Fein, dachte ich,
versuchen wir's mal so:
Alias Lötlackl schrieb:> Aber:> ist's so auch richtig?
Verzeihe bitte die Ironie:
Ist das das Fach "Theoretische Programmierung"? Oder ist der Compiler
heute nacht irgendwie stromlos geworden?
Alias Lötlackl schrieb:> Ich habe hier in einem Programm auf einem attyni2313 den Bedarf eines> Flagbytes und einer 16-bit globalen Variablen.
Warum zum Geier[tm] müssen die unbedingt in einem IO-Register
liegen?
@Jörg
Die GPIO-Register sind doch von Atmel extra dafür gedacht, um globale
Variablen zu speichern und um auf einzelne Bits in diesen zugreifen zu
können.
"This is a general purpose register that can be used to store data such
as global variables in the bit accessible I/O memory space."
Auszug aus dem Datenblatt vom AtXMega, beim AtTiny wird es wohl nicht
anders sein.
netb schrieb:> Die GPIO-Register sind doch von Atmel extra dafür gedacht, um globale> Variablen zu speichern und um auf einzelne Bits in diesen zugreifen zu> können.
Kann ja sein, aber das heißt doch nicht, dass das der einzige
Weg wäre, um eine simple globale Variable unterzubekommen. Normal
lässt man die einfach erstmal da, wo sie der Compilter hinpackt:
im unteren Bereich des SRAMs.
So ein GPIOR benutzt man bestenfalls dann mal, wenn es wirklich beim
Zugriff auf jeden Takt ankommt, sodass es Sinn hat, die Möglichkeiten
der Befehle CBI/SBI/SBIS/CBIS auszunutzen, weil man vielleicht dann
in einer ISR ein paar push/pop-Befehle dadurch einspart.
Nun ja, die AtTinys sind ja nun nicht gerade reicht mit SRAM gesegnet,
da machen solche extra Register durchaus mehr Sinn als im AtXMega. Aber
der Vorteil der schnellen Bitadressierung ist auch dort nicht zu
verachten.
Grundsätzlich ist es ja nicht falsch die Möglichkeiten zu nutzen, die
Atmel einem da bietet. Man erkauft es sich halt durch eine stärkere
Gebundenheit des Programmes an diese eine Architektur von µC, die diese
Register aufweisen.
Die Sinnhaftigkeit der Verwendung lasse ich mal dahingestellt.
Meine Frage ging eigentlich dahingehend, wie man den Ausdruck mit den
vielen Sternchen eigentlich zu verstehen hat (Der Adressoperator ist mir
auch nicht entgangen). Ist schon blöd, wenn man nicht wirklich weiß, was
man da so macht.
mfg
Alias Lötlackl schrieb:> Meine Frage ging eigentlich dahingehend, wie man den Ausdruck mit den> vielen Sternchen eigentlich zu verstehen hat
Wo sind denn da viele Sterne?
Das ist ein ganz normales Umcasten eines Pointers auf einen anderen
Datentyp-Pointer und Zugriff über den umgecasteten Pointer.
Wenn dir das Schwierigkeiten macht, dann
* lass die GPdingsda Register erst mal links liegen
* lies ein C-Buch
> Ist schon blöd, wenn man nicht wirklich weiß, was> man da so macht.
Noch ein Grund mehr zu einem C-Buch zu greifen und die Grundlagen zu
lernen.
netb schrieb:> Aber> der Vorteil der schnellen Bitadressierung ist auch dort nicht zu> verachten.
Der Versuch, da eine 16-bit-Variable reinzulegen, führt diese Idee
(die eigentlich der Anlass für die GPIORs überhaupt war) komplett
ad absurdum.
Jörg Wunsch schrieb:> Der Versuch, da eine 16-bit-Variable reinzulegen, führt diese Idee> (die eigentlich der Anlass für die GPIORs überhaupt war) komplett> ad absurdum.
Keine Ahnung, was der Threadersteller nun damit vor hat. Gibt es denn
aus deiner Sicht einen guten Grund diese Register nicht zu benutzen?
netb schrieb:> Gibt es denn> aus deiner Sicht einen guten Grund diese Register nicht zu benutzen?
Code obfuscation. Der Quellcode wird unnötig kompliziert. Ich
würde daher auf das GPIOR nur zurückgreifen, wenn es entweder auf
die zwei Byte wahrhaftig ankommt, oder aber für Fälle, wo die GPIORs
ihren eigentlichen Vorteil der Bitadressierbarkeit ausspielen können
(also z. B. für Flags in der Kommunikation zwischen ISR und dem
Rest der Applikation).
Jörg Wunsch schrieb:> Code obfuscation. Der Quellcode wird unnötig kompliziert. Ich> würde daher auf das GPIOR nur zurückgreifen, wenn es entweder auf> die zwei Byte wahrhaftig ankommt, oder aber für Fälle, wo die GPIORs> ihren eigentlichen Vorteil der Bitadressierbarkeit ausspielen können> (also z. B. für Flags in der Kommunikation zwischen ISR und dem> Rest der Applikation).
Vor allem geht es mir um's Verständnis. Ob ich diese Register in meinem
Programm nun wirklich unbedingt benötige, oder aber nur (für mich) neues
probieren will, sollte eigentlich absolut keine Rolle spielen! Antworten
like
Karl heinz Buchegger schrieb:> Wenn dir das Schwierigkeiten macht, dann> * lass die GPdingsda Register erst mal links liegen> * lies ein C-Buch
sind dann natürlich nicht sonderlich hilfreich, selbst in
Kernighan&Ritchie werden solch verschachtelten Konstrukte nicht
unbedingt aufgelöst.
Ich lese hier schon 'ne ganze Weile mit, aber solche Antworten von einem
ansonsten immer hilfsbereiten Karl heinz Buchegger geht mir dann schon
irgendwie auf die Eier. Es tut mir ja wirklich leid, aber 'ne sachliche
Erklärung dieses (aus meiner Sicht wild verschachteltem) geCaste hätte
mir völlig genügt.
mfg
PS: mache sowas nicht beruflich, bin eher der "lonely home hacker",
sozusagen Extremhobby, you know?
** Lötlackl schrieb:> Antworten like>> Karl heinz Buchegger schrieb:>> Wenn dir das Schwierigkeiten macht, dann>> * lass die GPdingsda Register erst mal links liegen>> * lies ein C-Buch>> sind dann natürlich nicht sonderlich hilfreich, selbst in> Kernighan&Ritchie werden solch verschachtelten Konstrukte nicht> unbedingt aufgelöst.
Die sind aber auch nur Kombinationen aus mehreren einfacheren
Konstrukten. Du wirst kein Buch finden, wo jeder mögliche C-Konstrukt im
Detail erklärt wird. Deshalb ist es besser, die Grundlagen zu kennen,
damit man damit dann selbst so einen Konstrukt auflösen kann. Und das
steht garantiert in diesem Buch drin.
> Ich lese hier schon 'ne ganze Weile mit, aber solche Antworten von einem> ansonsten immer hilfsbereiten Karl heinz Buchegger geht mir dann schon> irgendwie auf die Eier.
Das liegt daran, daß du die Antwort nicht verstanden hast.
> Es tut mir ja wirklich leid, aber 'ne sachliche Erklärung dieses (aus> meiner Sicht wild verschachteltem) geCaste hätte mir völlig genügt.
Du kennst dieses Sprichwort à la "teach a man to fish"?
** Lötlackl schrieb:> Es tut mir ja wirklich leid, aber 'ne sachliche> Erklärung dieses (aus meiner Sicht wild verschachteltem) geCaste hätte> mir völlig genügt.
Der Fall oben ist aber nicht wild verschachtelt, das ist eine einfache
Dereferenzierung eines gecasteten Pointers. Dieser Fall sollte in jedem
halbwegs brauchbaren C-Buch behandelt werden.
Für wirklich "haarige" Sachen gibt es Tools, z.B. cdecl (ursprünglich
Commandline, online benutzbar unter http://www.cdecl.org/):
1
cdecl> explain int (*foo(int (*[])(), int))()
2
declare foo as function (array of pointer to function returning int, int) returning pointer to function returning int
3
cdecl> declare foo as function (bar as array of pointer to function returning int, idx as int) returning pointer to function returning int
Andreas Ferber schrieb:> Der Fall oben ist aber nicht wild verschachtelt, das ist eine einfache> Dereferenzierung eines gecasteten Pointers. Dieser Fall sollte in jedem> halbwegs brauchbaren C-Buch behandelt werden.>> Für wirklich "haarige" Sachen gibt es Tools, z.B. cdecl (ursprünglich> Commandline, online benutzbar unter http://www.cdecl.org/):
Naja, einen C-Ausdruch anstatt in einen abstrakten Syntaxbaum nach
Englisch zu parsen ist nicht wirklich erhellend...
Konkret scheint das cdecl für das obige Konstrukt etwas überfordert.
Gehen wir aus vom einem C-Beispiel wie
die im cdecl.org in allen Varianten zu einem Syntaxfahler führt -- auch
ohne die Zuweisung und mit unsigned short für uint16_t etc.
(Ersetzungen, die für avr-gcc nichtmal zutreffen. Was da an Text
raussprudeln würde ... naja.
** Lötlackl schrieb:> sind dann natürlich nicht sonderlich hilfreich, selbst in> Kernighan&Ritchie werden solch verschachtelten Konstrukte nicht> unbedingt aufgelöst.
Was ist da drann verschachtelt?
Wenn
int* pI;
pI ein Pointer auf einen int ist, dann bekommt man mit
*pI
den Wert, also den Integer, auf den pI zeigt. Stink normale Pointer
Dereferenzierung. Steht in jedem Buch.
Jetzt haben wir keinen Pointer sondern eine Variable.
int a;
mittels
&a
bekommt man die Adresse der Variablen, vulgo einen Pointer auf a.
Steht auch in jedem Lehrbuch.
*&a;
liefert daher den Inhalt von a. Denn wortwörtlich steht da
a nimmm a
&a die Adresse von a
*&a hol den Wert, der sich an der Adresse von a
verbirgt.
Nun, der Wert der an der Adresse von a steht, das ist der Wert von a.
Das steht so vielleicht nicht in einem Lehrbuch, wenn man aber die
beiden Konzepte des Derefernzierungs-* und des Adressoperators
verstanden hat, sollte man eigentlich keine Schwierigkeiten haben, die
beiden Konzepte zu verbinden.
Das ist ungefähr so, wie jedem Volksschüler relativ bald klar ist, dass
9 * 5 / 5
wieder 9 ergibt, weil / die Umkehrung der Multiplikation ist.
Das einzige was man sich in C angewöhnen muss, ist: solche Ausdrücke
immer beim Variablennamen anfangen auseinanderzunehmen. Das steht so
vielleicht nicht in deinem Lehrbuch.
Und das '*&irgendwas' ein sinnvolles Konstrukt ist und gleichwertig zu
'irgendwas' ist, während '&*irgendwas' kein sinnvolles Konstrukt ist,
weil ein Wert per se erst mal keine Speicheradresse hat.
Bleibt noch der Mittelteil. Das ist ein Datentypausdruck, der in ( )
eingeschlossen ist. Und das ist gemein hin bekannt als ein Cast. Mit
einem Cast kann man einen Datentypwechsel erzwingen. In die Klammern
schreibt man den Datentyp, auf den der rechts vom Cast stehende Ausdruck
gewzungen werden soll. Steht auch in jedem Lehrbuch.
(double)a
erzwingt, dass der Wert von a auf den Datentyp double gebracht wird. a
wird ausgelesen und ergibt irgendeinen Wert. Dieser Wert wird zu einem
double gemacht und mit diesem double wird weitergearbeitet.
(int*) &a
erwzingt also, dass die Adresse von a als vom Datentyp 'Pointer auf int'
aufgefasst wird.
Das ist in diesem Fall natürlich sinnlos, weil &a ja sowieso schon ein
Pointer auf int ist, aber seis drum. Wir hätten auch schreiben können
(double*) &a
jetzt wird veranlasst, dass die Adresse von a auf einen 'Pointer auf
double' umgecastet wird. Wird dieser neue Pointer dereferenziert
* (double*) &a
so zwinge ich den Compiler dadurch, so zu tun, als ob dort wo die
Variable a im Speicher liegt, die Bytes wie ein double Wert aufgefasst
werden. Der Zahlenwert wird nicht konvertiert oder sonst irgendwie
umgeformt, sondern ich tu einfach so, als ob dort im Speicher die Bytes
für einen double Wert vorliegen würden und lese sie als double Wert, was
auch immer das ergibt.
Es ist im Grunde fast so, als ob ich auf eine Bierkiste deute und zu dir
sage: Jetzt tun wir mal so, als ob an der Stelle an der die Bierkiste
steht ein Sessel wäre, auf den du dich setzen kannst.
* (Sessel*) &Bierkiste
Die Bierkiste ist immer noch eine Bierkiste, aber durch den Cast sehen
wir den Platz auf dem die Bierkiste steht so an, als ob dort ein Sessel
stünde.
Auch das steht in jedem Lehrbuch. Vielleicht nicht ganz in dieser Form,
aber irgendwo kommt das mit Sicherheit vor.
Aber Achtung:
(double)a
und
*(double*)&a
sind 2 verschiedene Dinge!
Das eine mal wird a in seiner ganzen Pracht ausgelesen und das
Ausgelesene in einen double umgeformt, während man im zweiten Fall nur
so tut, als ob dort wo a im Speicher liegt, ein double Wert vorliegen
würde. Da wird kein Zahlenwert in irgendeiner Form umgeformt, es werden
lediglich die Bytes im Speicher anders intepretiert.
> ansonsten immer hilfsbereiten Karl heinz Buchegger geht mir dann schon> irgendwie auf die Eier.
Was glaubst du wie es mir mitlerweile auf die Eier geht, jeden Tag immer
wieder dieselben Fragen zu beantworten, die in jeden, aber auch wirklich
jedem, Lehrbuch beantwortet werden?
Wenn jemand ein Buch liest und mit einem Konzept Schwierigkeiten hat und
eine nähere Erläuterung dazu braucht: Super, gerne!
Aber wenn man zum hundertausendstenmal erklären muss warum bei
double i = 5 / 9;
null herauskommt, dann wird man irgendwann müde.
Dein Problem fällt in die gleiche Kategorie. Es ist einfach nur das
Verbinden der Konzepte
AdressOf
Casten
Dereferenzieren
zu einer Einheit, mehr steckt da nicht dahinter. Aber eine Aussage ala
'Mich bringen die viele * durcheinander' zeigt mir, dass schon die
Einzelkonzepte Schwierigkeiten machen. Und die sind in jedem Lehrbuch
enthalten. Oder was würdest du zu jemandem sagen, der auf die
Aufgabenstellung
Differential( 2 * x + 7, dx )
mit 'Ähm was bedeutet der * da drinnen' antwortet. Ich wette du würdest
ihm auch erst einmal ein Grundlagenlehrbuch über Grundschulmathematik in
die Hand drücken und nicht damit anfangen ihm die Feinheiten der
Differentatiation zu erklären.
Johann L. schrieb:> Konkret scheint das cdecl für das obige Konstrukt etwas überfordert.
Was dadran liegen könnte, dass cdecl nur Deklarationen und Casts kann,
keine kompletten Ausdrücke ;-)
cdecl war nicht als "Allheilmittel" gemeint, nur als Beispiel für ein
mögliches Hilfsmittel. Im konkreten Fall hilft es nicht, richtig, aber
der Fall ist ja auch nicht "haarig" ;-)
Andreas