Hallo, mal eine Frage zu Pointern ins Flash beim AVR: Gibt es überhaupt einen Unterschied zwischen Pointern, in ins RAM zeigen und Pointer, die ins FLASH zeigen? Es gibt zwar in AVRGCC die Pointer PGM_P und PGM_VOID_P, aber mir ist aufgefallen, daß man statt diesen auch "normale" Pointer benutzen kann. Der eigentliche Unterschied ob RAM oder FLASH liegt dann nur noch in der Routine (z.B. ob memcpy() oder memcpy_P() ). Grüße, Sebastian
Beim AVR ist Programmspeicher nicht das gleiche wie der Datenspeicher - daher sind Pointer auf RAM in der Tat was anderes als Pointer auf FLASH. Das ist ziemlich heimtückisch.
Beim aktuellen avr-gcc sind Pointer 'auf Flash' und Pointer 'auf RAM' eben nicht wirklich "was anderes", denn dann gaebe es die ganze "progmem"-Verwirrungen nicht, die hier und in anderen Foren immer wieder auftreten, und man bzw. der Compiler und die Laufzeitbibliotheksfunktionen koennten einem Pointer irgendwie "ansehen" worauf er zeigt und ensprechenden Code generieren/nutzen.
Ich erinnere mich dunkel, daß es beim Keil C51-Compiler einen "Generic Pointer" gab, der 3 Bytes belegt. Dabei waren 2 Bytes für die Adresse und das 3.Byte gab den Speicher-Typ an (IDATA, XDATA und CODE). Aber wenn ich es richtig verstehe, gibt es beim AVR-GCC keinen Unterschied zwischen RAM- und ROM-Pointern, da beide nur 2 Bytes für die Adresse haben, oder? Grüße, Sebastian
Wenn RAM- und ROM-Pointer nur zwei Bytes belegen, muss man bei deren Gebrauch aber höllisch aufpassen, daß man die nicht verwechselt - sonst geht's in die Hose, da sie nicht auswechselbar verwendet werden dürfen. Damit sind die Pointer definitiv was unterschiedliches - auch wenn's der Compiler nicht auseinanderhalten kann. Die Unterscheidung muss also durch den Programmierer aufrechterhalten werden; schafft der's nicht, geht so einiges in die Hose. Also braucht man entweder von allen Funktionen, denen Pointer übergeben werden können zwei Ausführungen (mit RAM- und mit ROM-Pointer) oder man muss ineffiziente Umkopieraktionen durchführen. Was für eine Grütze. Aber verständlich; das 3-Byte-Pointer-Konzept ist in der Tat ineffizient, da ja bei Laufzeit bei jedem Pointerzugriff erst einmal nachgesehen werden muss, worum es sich dabei handelt ... Diese Architektur mit getrenntem Code/Datenspeicher ist vielleicht doch nicht die allerpraktischste, oder?
Genauso ist es. Es gibt wohl einen C-Standard-Vorschlag für distinct memory spaces, und einen Willigen, der dies im längeren Zeitrahmen im GCC implementieren möchte (Svein Seldal). Damit sollte der Compiler dann auch in der Lage sein, die Zeiger zumindest auseinanderzuhalten, d. h. eine Warnung zu generieren, wenn man einen Zeiger in den falschen memory space benutzt. Bis dahin ist die Unterscheidung ausschließlich im Kopf des Programmierers. Manche Compiler (wie IAR) helfen dem Programmierer mit einigen Automatismen mehr (z. B. beim Dereferenzieren), aber die Auswahl der korrekten Routine obliegt dennoch dem Programmierer.
"Damit sind die Pointer definitiv was unterschiedliches - auch wenn's der Compiler nicht auseinanderhalten kann." "Genaus so ist es" Hmm, was ist nach so definitiven Aussagen denn genau der Unterschied. Ich frage nicht, wie mit den Addressangaben umzugehen ist oder was man im Kopf haben muss, nur wo der definitive Unterschied ist, bezogen auf die Pointer selbst.
Ein Pointer ist für den Compiler ein 16-Bit-Wert. Um diesen korrekt nutzen zu können, muss der Compiler wissen, ob dieser Pointer auf RAM oder ROM zeigt - die nämlich liegen nicht im gleichen Adressraum. Damit ist ein ROM-Pointer mit dem Wert 0x1234 was anderes als ein RAM-Pointer mit dem gleichen Wert. Das heimtückische ist, daß man das dem Wert nicht ansehen kann. Bevor man einen Pointer verwendet, muss man also sehr genau wissen, worauf er zeigt bzw. worauf er zeigen soll. Eine Funktion wie puts() erwartet als Argument einen Pointer - und zwar aller Wahrscheinlichkeit nach einen RAM-Pointer. Also muss man einen String aus dem ROM erstmal ins RAM kopieren, damit man puts() aufrufen kann - oder man muss eine puts()-Variante implementieren, die ROM-Pointer verarbeitet. Würde der Compiler wenigstens zur Übersetzungszeit RAM- und ROM-Pointer unterscheiden können, dann würden Aufrufe von Funktionen wie puts() mit ROM-Pointern wenigstens mit entsprechenden Fehlermeldungen quittiert - das aber ist, wenn ich J. Wunsch korrekt interpretiere, in GCC noch lange nicht implementiert. Damit wird den C-Anfängern hier im Forum noch ein ganz besonderer Knüppel zwischen die Beine geworfen, vor allem, wenn C-Fragen von Leuten beantwortet werden, die C zwar mit der Muttermilch aufgesogen haben, aber eben "normale" Prozessoren damit programmieren ...
Martin, es gibt derzeit nur einen Unterschied, der liegt in der Definition dieser Objekte: all diese PGMSPACE usw. Makros expandieren letztlich zu einem __attribute__((_progmem_)), was den Compiler veranlasst, die derart definierten Objekte in eine separate section im ELF-File einzusortieren. Ich glaube, es gibt noch einen zweiten Unterschied, dass für deren zur Compilezeit erfolgendes Dereferenzieren der pm-Operator im Assemblercode benutzt wird. Dadurch funktionieren eben solche Dinge wie menu[2], obwohl menu[i] nicht mehr funktioniert (mit i != const). Ansonsten sind damit definierte Zeiger aber in der Tat hernach für den Compiler ,,ganz normale'' Zeiger.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.