Forum: Compiler & IDEs Alter Code mit prog_char und neue avr-libc


von Wilhelm K. (Gast)


Lesenswert?

1
const prog_char * String_im_Flash;

Das geht so nicht mehr, weil man in der Doku der aktuellen avr-libc 
findet:
1
Typedef Documentation
2
prog_char 
3
4
Note:
5
DEPRECATED
6
This typedef is now deprecated because the usage of the __progmem__
7
 attribute on a type is not supported in GCC. However, the use of the
8
 __progmem__ attribute on a variable declaration is supported, and this 
9
is now the recommended usage.
10
11
The typedef is only visible if the macro __PROG_TYPES_COMPAT__ has been
12
 defined before including <avr/pgmspace.h> (either by a #define directive,
13
or by a -D compiler option.)
14
15
Type of a "char" object located in flash ROM.
1
#define __PROG_TYPES_COMPAT__
möchte ich nicht benutzen, allerdings scheitere ich daran, das neu zu 
schreiben, weil ich nicht weis (Anfänger), wie man das
1
__progmem__
Attribut auf die Variable anwendet.

Wer weis wie's geht?

von g457 (Gast)


Lesenswert?

> Wer weis wie's geht?

Der letzte Absatz vor dem von Dir zitierten :-) -> PROGMEM an die 
entsprechenden Stellen verteilen.

HTH

von Wilhelm K. (Gast)


Lesenswert?

1
const prog_char * String_im_Flash __attribute__((__progmem__))

Ist das so richtig?

von Wilhelm K. (Gast)


Lesenswert?

Ich meinte so:
1
const char *String_im_Flash __attribute__((__progmem__))

von Stefan E. (sternst)


Lesenswert?

Wilhelm K. schrieb:
> Ich meinte so:
1
const char *String_im_Flash __attribute__((__progmem__))

Nein, das legt den Pointer selber ins Flash.
Einfach nur:
1
const char *String_im_Flash;
Das PROGMEM als Teil eines Pointer-Targets war eh immer nur Kosmetik.

von Wilhelm K. (Gast)


Lesenswert?

Uuuups! Das verblüfft mich nun total. Wie kann man dann noch 
unterscheiden, ob eine Variable im SRAM oder im Flash liegt?

Das kapiere ich überhaupt nicht.

von Stefan E. (sternst)


Lesenswert?

Wilhelm K. schrieb:
> Uuuups! Das verblüfft mich nun total. Wie kann man dann noch
> unterscheiden, ob eine Variable im SRAM oder im Flash liegt?

Bei einem Pointer entscheidet die Art des Zugriffs darüber, ob er ins 
Flash oder RAM zeigt:
*Pointer -> Pointer ins RAM
pgm_read_XXXX(Pointer) -> Pointer ins Flash

von Karl H. (kbuchegg)


Lesenswert?

Wilhelm K. schrieb:
> Uuuups! Das verblüfft mich nun total. Wie kann man dann noch
> unterscheiden, ob eine Variable im SRAM oder im Flash liegt?
>
> Das kapiere ich überhaupt nicht.


Du hattest hier einen Sonderfall.

Das hier ist ein Pointer. Ein Pointer ist aber nichts anderes als ein 
Verweis auf einen anderen Speicher.
D.h. bei einem Pointer musst du unterscheiden: Was genau liegt den 
eigentlich im Flash? Der Pointer selber, oder das worauf er zeigt?


    Pointer
    +-------+                       +---+---+---+---+---+
    |  o--------------------------->|   |   |   |   |   |
    +-------+                       +---+---+---+---+---+

Bei

const prog_char * String_im_Flash;

liegt nicht der Pointer (mit Namen String_im_Flash) im Flash (der linke 
Teil der Grafik), sondern die Character (der rechte Teil der Grafik).

Die Deklaration liest sich so

                 String_im_Flash       da ist eine Variable

               * String_im_Flash       und diese Variable ist ein
                                       Pointer

      prog_char * String_im_Flash      das worauf er zeigt, liegt im
                                       Flash ...

char prog_char * String_im_Flash       ... und zwar sind das Character

> Wie kann man dann noch unterscheiden, ob eine Variable
> im SRAM oder im Flash liegt?

Schau dir die Deklaration der Variablen an

int i PROGMEM;
          Das ist eine Variable i und die liegt im Flash

int * pI;
          Da ist ein Pointer und dieser Pointer zeigt auf einen int

int * pJ PROGMEM;
          Noch ein Pointer. Aber diesmal liegt die Pointervariable
          selbst im Flash.


Wie schon gesagt: das prog_char war kosmetischer Natur. Effektiv hat es 
nichts bewirkt ausser der (eher zweifelhaften) Dokumentation, dass ein 
Pointer auf etwas zeigt, was im Flash liegt. Das ist aber etwas, was du 
sowieso wissen musst. Ob pI auf einen Integer im SRAM oder im Flash 
zeigt, musst du selbst wissen, da kann dich der Compiler nicht 
unterstützen.

von Martink11 M. (Firma: google) (martink11) Flattr this


Lesenswert?

gibt es nicht die möglichkeit im Studio 6 etwas umzustellen?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Martin 567 schrieb:
> gibt es nicht die möglichkeit im Studio 6 etwas umzustellen?

Du willst alse explizit, dass Code mit undefiniertem Verhalten 
akzeptiert wird? Dann siehe oben: -D__PROG_TYPES_COMPAT__ als 
Compiler-Option ist dein schlechter Freund.

Wilhelm K. schrieb:
> Uuuups! Das verblüfft mich nun total. Wie kann man dann noch
> unterscheiden, ob eine Variable im SRAM oder im Flash liegt?

PROGMEM aka. __attribute__((progmem)) funktioniert ähnlich wie das 
section-Attribut:  Es bestimmt die Ablage, d.h. die Section, des damit 
markierten Objekts.

Im folgenden Beispiel liegen alle p1...p4 im Flash (Section 
.progmem.data, denn PROGMEM wirkt auf das jeweils definierte Objekt, 
nämlich p1...p4:
 
1
#include <stdlib.h>
2
#include <avr/pgmspace.h>
3
4
// p1 liegt im Flash (.progmem.data) und wird mit
5
// NULL initialisiert.
6
char * const p1 PROGMEM = NULL; 
7
8
// p2 liegt im Flash und wird mit der Adresse eines
9
// String-Literals initialisier, das "P2" enthält.
10
// Das Literal liegt im RAM (.rodata).
11
char * const p2 PROGMEM = "P2"; 
12
13
// p3 liegt im Flash und wird mit "P3" initialisiert.
14
char const p3[] PROGMEM = "P3"; 
15
16
// p4 liegt im Flash und wird mit der Adresse eines
17
// String-Literals initialisier, das "P4" enthält.
18
// Das Literal liegt im RAM (.rodata).
19
const char PROGMEM * const p4 = "P4";
  
Am Beispiel p4 sieht man, daß prog_char nicht einfach durch char PROGMEM 
ersetzt werden darf.

Ich rate davon ab,  __PROG_TYPES_COMPAT__ zu verwenden, denn das progmem 
in Typedefs hatte nie ein definiertes/dokumentiertes Verhalten.  Die 
GCC-Dokumentation definiert diese Attribut ausschließlich für 
Deklarationen und nicht für Typen.

Man kann nun auf avr-gcc schimpfen und fragen, warum er progmem in 
typedef je akzeptiert hat.  Das war ein Designfehler, der nicht 
korrigiert wurde, weil niemand ihn als so wichtig erachtete, es in 
avr-gcc einzupflegen.

Die AVR-Libc wiederum hat das Feature fleissig verwendet nach dem Motto 
"alles was keine Warnung bringt ist in Ordnung", obwohl progmem für 
Typen nie dokumentiert war.  Es ist einzig und allen für Deklarationen 
dokumentiert und im Compiler unterstützt.

Ich für meinen Teil verwende die Zeit, die ich auf avr-gcc verwende, 
lieber auf Dinge, die den Compiler weiter bringen, anstatt Aufwand in 
Features zu stecken, die nie dokumentiert waren und auch keine neue 
Funktionalität bringen.

Jeder, der seine Prioritäten bei der avr-gcc Entwicklung anders gesetzt 
hat, kann natürlich die entsprechende Erweiterung zum Compiler 
beitragen.

Und die Anwender von avr-gcc sind gut damit beraten, die Dokumentation 
zu lesen...

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Johann L. schrieb:
> Die AVR-Libc wiederum hat das Feature fleissig verwendet nach dem Motto
> "alles was keine Warnung bringt ist in Ordnung", obwohl progmem für
> Typen nie dokumentiert war.

Sagen wir mal so: es scheint erstmal naheliegend zu sein, ein typedef
dafür zu verwenden, und es hat einfach niemand hinterfragt, ob das
überhaupt technisch in Ordnung ist.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jörg Wunsch schrieb:
> Johann L. schrieb:
>> Die AVR-Libc wiederum hat das Feature fleissig verwendet nach dem Motto
>> "alles was keine Warnung bringt ist in Ordnung", obwohl progmem für
>> Typen nie dokumentiert war.
>
> Sagen wir mal so: es scheint erstmal naheliegend zu sein, ein typedef
> dafür zu verwenden, und es hat einfach niemand hinterfragt, ob das
> überhaupt technisch in Ordnung ist.

Zugegeben; die Dokumentation im GCC-Manual war sicherlich nicht 
erschöpfend. Inzwischen sollte sich die Situation aber deutlich 
verbessert haben.

Eine ganz ähnliche Tretmine war die gleichzeitige Verwendung von signal 
und interrupt in ISR... aua

Natürlich kann man sich beschweren, wenn der Compiler da nicht gleich 
gemeckert hat.  Und auch darüber, wenn AVR-Maintainer 
nicht-dokumentierte Erweiterungen akzeptieren, Beispiel OS_task und 
OS_main (Ok, Anatoly ist ja selbst Maintainer...)

Aber Undokumentiertes zu verwenden und nach Sichtprüfung zu verwenden 
ist eigentlich immer ein Vabanque-Spiel.

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.