Forum: Compiler & IDEs Pointer und PROGMEM.


von John S. (student)


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

von Johannes M. (johnny-m)


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...

von daniel (Gast)


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

von daniel (Gast)


Lesenswert?

const int  const  pfeld = feld; // geht wieder
const int  const  const pfeld = feld; // auch

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

von Johannes M. (johnny-m)


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...

von John S. (student)


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

von die ??? (Gast)


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:

1
#include <pgmspace.h>
2
3
prog_uint8_t Gleisbild1[11616] = 
4
  {
5
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
6
    0xFF, 0xFF, 0xFF, 0xFF, ...... 
7
  };
8
9
prog_uint8_t* PtrGleisbild;
10
11
void 
12
Map_Pixel( ... , prog_uint8_t* xyz, ...);
13
14
  // ...
15
16
  PtrGleisbild =  &Gleisbild1[0];
17
18
  // ...
19
20
  Map_Pixel (... , PtrGleisbild, ...);
21
22
  // ...

von die ??? (Gast)


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.

von John S. (student)


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

von John S. (student)


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:
>
>
>
1
> #include <pgmspace.h>
2
> 
3
> prog_uint8_t Gleisbild1[11616] =
4
>   {
5
>     0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
6
> 0xFF,
7
>     0xFF, 0xFF, 0xFF, 0xFF, ......
8
>   };
9
> 
10
> prog_uint8_t* PtrGleisbild;
11
> 
12
> void
13
> Map_Pixel( ... , prog_uint8_t* xyz, ...);
14
> 
15
>   // ...
16
> 
17
>   PtrGleisbild =  &Gleisbild1[0];
18
> 
19
>   // ...
20
> 
21
>   Map_Pixel (... , PtrGleisbild, ...);
22
> 
23
>   // ...
24
>

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

von PeterP (Gast)


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.

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
Noch kein Account? Hier anmelden.