www.mikrocontroller.net

Forum: Compiler & IDEs Pointer und PROGMEM.


Autor: John Schmitz (student)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen, brauche mal wieder Eure Unterstützung:

Folgendes gilt:
----------------------
const unsigned char Gleisbild1[11616] PROGMEM = {

0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, ...... }

prog_uint8_t *PtrGleisbild;

void Map_Pixel( ... , const prog_uint8_t xyz[], ...);

PtrGleisbild =  &Gleisbild1[0]; // dies ist Zeile 209 !!!!!!

Map_Pixel (... , PtrGleisbild, ...);

-----------------------

Und nun meckert GCC mit WARNING

../test.c:209: warning: assignment discards qualifiers from pointer 
target type


Programm läuft aber prima - wie bitte bekomme ich WARNING weg ?

Vielen Dank im voraus und Grüsse

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun, PtrGleisbild ist ein Pointer auf einen prog_uint8_t während 
Gleisbild vom Typ const unsigned char ist, was aus Sicht des 
Compilers nicht dasselbe ist. Die Warnung an sich bezieht sich 
eigentlich nur auf den Typqualifizierer const , den Du mit der 
Zuweisung "wegschmeißt" (engl. to discard -> wegwerfen).

Entweder lässt Du die Warnung ne Warnung sein (sie ist, wie Du selber 
schon gemerkt hast, kein Fehler) oder Du passt die Typen an. Gibt es 
einen Grund, Gleisbild nicht als prog_uint8_t zu deklarieren?

Du könntest natürlich auch den Pointer als Pointer auf const 
deklarieren. Viele Wege führen nach Rom...

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
sehr ricchtig was gcc macht
ich meine dass sollte sogar ein error sein

int c=5;
const int * pc = &c; // eine freiwillige einschräkung

const int c=5;
const int * pc = &c; // notwenigkeit

du solltest dich mit constness in c++ auseinandersetzen
dann verstehst du warum zb folgendes auch nicht geht

int ** feld;
const int ** pfeld = feld; // error

nun als tipp
const int const pfeld = feld; // geht wieder
const int const const pfeld = feld; // auch

was ich nicht weiss ist, ob die tatsache dass
feld im eeprom liegt, eine zusätztliche deklaration
für den zeiger erfordet. damit der compiler nicht denkt
die variavle liege in sram.

grüsse, daniel

Autor: daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
const int  const  pfeld = feld; // geht wieder
const int  const  const pfeld = feld; // auch

die hervorhebungsfunktion mit  WORT  hat
den code verfälscht ;)

Autor: Johannes M. (johnny-m)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
daniel wrote:
> sehr ricchtig was gcc macht
> ich meine dass sollte sogar ein error sein
Im Prinzip kann dabei aber nicht viel passieren, weshalb ne Warnung 
eigentlich ausreichend ist. In 99% der Fälle dürfte hier das Programm 
das machen, was der Programmierer erreichen wollte...

> du solltest dich mit constness in c++ auseinandersetzen
> dann verstehst du warum zb folgendes auch nicht geht
Nun, zunächst mal ist das C und kein C++, aber ansonsten stimme ich Dir 
zu.

> was ich nicht weiss ist, ob die tatsache dass
> feld im eeprom liegt, eine zusätztliche deklaration
> für den zeiger erfordet. damit der compiler nicht denkt
> die variavle liege in sram.
Wieso EEPROM? Es geht hier ums Flash (Programmspeicher). Und durch das 
Attribut PROGMEM wird dem Compiler auch mitgeteilt, dass Variable und 
Zeiger im Flash liegen (der Spezial-Datentyp prog_uint8_t enthält das 
Attribut bereits).

> die hervorhebungsfunktion mit  WORT  hat
> den code verfälscht ;)
Und warum formatierst Du den Code nicht gleich vernünftig als C-Code? 
Dann wird auch nix verfälscht...

Autor: John Schmitz (student)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke an alle,

soweit ich es nun verstanden habe, ist "const" (und nicht der mismatch 
von "uint8" mit "char") die Ursache. Nun sind die Daten im Flash aber 
sowieso const - oder habe ich da etwas nicht verstanden ? Das weiss der 
Compiler doch - oder ?

Wenn ich nun "const" weglasse, dann sage ich doch implizit, dass ich den 
Speicherbereich als RAM ansehe - oder sehe ich die Dinge zu einfach ???

Grüsse

Autor: die ??? (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du dem Compiler sagst, dass der Wert und die Adresse konstant ist, 
dann weiss er es. Ich würde es wie folgt machen, so sollte es konsistent 
sein:

#include <pgmspace.h>

prog_uint8_t Gleisbild1[11616] = 
  {
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0xFF, ...... 
  };

prog_uint8_t* PtrGleisbild;

void 
Map_Pixel( ... , prog_uint8_t* xyz, ...);

  // ...

  PtrGleisbild =  &Gleisbild1[0];

  // ...

  Map_Pixel (... , PtrGleisbild, ...);

  // ...

Autor: die ??? (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch ein kleiner Tip am Rande. In einem anderen Beitrag hast du 
geschrieben, dass du den Mega128 als Target nutzt. Nun sind deine Tables 
im Programmspeicher schon recht groß, du solltest aufpassen, dass ein 
zusammenhängendes Table nicht "auf der Grenze" 64KiB liegt. Da kann es 
Probleme geben wenn man das nicht beachtet.

Autor: John Schmitz (student)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die ??? wrote:
> Noch ein kleiner Tip am Rande. In einem anderen Beitrag hast du
> geschrieben, dass du den Mega128 als Target nutzt. Nun sind deine Tables
> im Programmspeicher schon recht groß, du solltest aufpassen, dass ein
> zusammenhängendes Table nicht "auf der Grenze" 64KiB liegt. Da kann es
> Probleme geben wenn man das nicht beachtet.

Au, da sprichst Du ein interesantes Theam an:

Ich habe 1. in Erinnerung, dass dies GCC abhängig ist und mit der 
neuesten Version das Problem nicht mehr aktuell ist ? Kann ich kaum 
glauben - habe ich etwas falsch verstanden ?

2. Welche Einflussmöglichkeiten habe ich denn (aus Studio4 heraus), den 
Speicherbereich in den 2. 64k Block zu moven? Dass es für diesen Berich 
extra Lesebefehle (Zugriffsbefehle) gibt, habe ich gelernt.

3. Was mache ich denn bei einem AT256 ? Da gibt es dann ja 4 * 64k 
Blöcke ... Kann ich nur 2 davon nutzen ?

Sicherlich silly Questions, aber dieses Theam ist für mich Neuland.

Grüsse

Autor: John Schmitz (student)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
die ??? wrote:
> Wenn du dem Compiler sagst, dass der Wert und die Adresse konstant ist,
> dann weiss er es. Ich würde es wie folgt machen, so sollte es konsistent
> sein:
>
>
>
> #include <pgmspace.h>
> 
> prog_uint8_t Gleisbild1[11616] =
>   {
>     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
> 0xFF,
>     0xFF, 0xFF, 0xFF, 0xFF, ......
>   };
> 
> prog_uint8_t* PtrGleisbild;
> 
> void
> Map_Pixel( ... , prog_uint8_t* xyz, ...);
> 
>   // ...
> 
>   PtrGleisbild =  &Gleisbild1[0];
> 
>   // ...
> 
>   Map_Pixel (... , PtrGleisbild, ...);
> 
>   // ...
> 

Sorry, dass ich mich erst jetzt wieder melde - habe Deinen Rat befolgt, 
jetzt ist alles o.k.

Aaaaaber - worin liegt denn nun der Unterschied ???

Im Flash liegen für den Compiler doch  immer nur Konstanten, da könnte 
man nun doch sagen, deswegen muss das 'const' unbedingt dahin, 
andererseits könnte man argumentieren, das 'const' kann man weglassen, 
es gibt ja keine andere Möglichkeit. Was ist nun richtig ?

Und daraus die eigentliche Frage:

Wann nehme ich denn nun das 'const' und wann nicht (im Flash natürlich) 
?

Hintergrund der Frage: Ich benutze einen wizzard, der aus dem gif Bild 
diese Noation mit 'const' macht ... und der Programmierer scheint mir 
nicht ganz doooof (kein kleiner Dummer ;-)) zu sein! Nun nehme ich es 
also heraus, damit ggc Ruhe gibt - und mit meinem restlichen Code 
logisch matcht - wo ist die Gefahr ?

Sorry, dass ich so nerve, aber ich will es verstehen.

Grüsse

Autor: PeterP (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein 'const' bewirkt zunaechst nur, dass eine Variable schreibegschuetzt 
wird, also nur initialisiert, aber nicht mehr veraendert werden kann.
Sie liegt aber weiter im RAM.

prog_uint8_t Gleisbild1...

erzeugt ein Array im Flash (was zwar implizit schreibgeschuetzt und 
effektiv, aber nicht explizit const ist).
("prog_uint8_t" expandiert zu "uint8_t PROGMEM"

const unsigned char Gleisbild1[11616] PROGMEM = ...

erzeugt hingegen ein Array im Flash, das explizit const ist. Entspricht 
also "const prog_uint8_t Gleisbild1"

prog_uint8_t* PtrGleisbild;

erzeugt hingegen einen Pointer auf ein prog_uint8_t, also ein uint8_t 
PROGMEM, der weder konstant ist, noch selber im Flash liegt und dessen 
Zieltyp auch nicht const ist (auch wenn er im Flash liegt und damit 
nicht ueberschreibbar ist).

Was die Typpruefung angeht (const oder nicht etc.) ist das das 
Progmem-Segment naemlich zunaechst einmal ein Segment wie jedes andere, 
wie _bss, _data oder wie auch immer. Das bei der Codegenerierung dann 
spaeter ein spezieller Zugriffsbefehl noetig ist, ist zunaechst 
irrelevant.
Daher der Fehler: Deine Initialisierung intitialisiert einen Pointer auf 
einen "uint8_t" mit einem pointer auf einen "const uint8_t", was fue 
rdie weitere Nutzung des Pointer die "const"-Eigenschaft des 
urspruenglichen Arrays aufhebt. Daher die Warnung.
Solange man im Code dann nicht schreibend auf das Ziel des Pointers 
zugreift, macht es keinen Unterschied. Der Compiler wuerde die 
Unmoeglichkeit aber u.U. nicht merken, da der spaeter verwendete Pointer 
ja nciht auf ein const-Element zeigt. "PtrGleisbild[0][0]=7" waere also 
eine gueltige Anweisung, nur der Assembler/Linker bekommt spaeter 
Probleme und man weiss nicht, warum.

Pointer sind ein kompliziertes Feld. Pointer auf Arrays umso mehr, 
Pointer auf Arrays von Pointern ganz besonders. Und wenn 'const' 
dazukommt, wird es noch komplexer. Von Attributen ganz zu schweigen.

Denn ist es nun ein constanter Pointer auf einen veraenderbaren Inhalt 
oder ein veraenderbarer Pointer auf constante Inhalte? oder beides?
Die Verwendung von Macros, die ihrerseits Attribute oder Qualifier 
hinzufuegen, macht die Sache noch komplizierter.

Am Besten, man sagt dem Compiler, er soll den Praeprozessor-Output nicht 
loeschen und schaut sich dann an, was der Praeprozessor nach Aufloesen 
aller Macros ausgespuckt hat. Das sieht zwar nicht schoen aus, aber es 
ist das, was der Compiler sieht und nicht das, was man glaubt, was er 
sieht.

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.