AVR: prog_char* == char* ?

Gast #178879
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
Gast
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.
Gast
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.
Gast
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
Gast
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?
Gast
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.
Gast
"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.
Gast
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 ...
Gast
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.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 21 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.