Forum: Compiler & IDEs Dummy für __flash bzw PROGMEN


von D a v i d K. (oekel) Benutzerseite


Lesenswert?

Hi,

ich würde gerne eine große Menge Strings, die ich für den  avr-gcc 
Compiler definiert habe im normalen gcc verwenden.

Daher bin ich auf der Suche nach einem geschickten Makro, dass mir diese 
attribute wieder entfernt/redefiniert.
1
...
2
#ifdef GCC
3
    #define __flash ?
4
    #define PROGMEM ??
5
#endif
6
7
const __flash cahr strHund[] = "Hund";
8
const char strKatze[] PROGMEM = "Katze";
9
...

Mir ist klar, dass ich alles doppelt definieren könnte a la:
1
...
2
#ifdef GCC
3
    const _cahr strHund[] = "Hund";
4
    const char strKatze[] = "Katze";
5
#else
6
const __flash cahr strHund[] = "Hund";
7
const char strKatze[] PROGMEM = "Katze";
8
#endif
9
...

Diese Pflege möchte ich mir jedoch sparen, auch wenn ein CnP mit 
modernen IDEs, die "Column Selection Mode" unterstützen recht schnell 
geht.

Grüße David

von Walter T. (nicolas)


Lesenswert?

Statt der <pgmspace.h> "include" ich in meinen gemischen Projekten die 
folgendete "pgmspace.h":
1
#ifndef PGMSPACE_H
2
    #define PGMSPACE_H
3
4
    #ifdef AVR
5
      #define constflash const __flash
6
    #include <avr/pgmspace.h>
7
        #include <stdio.h>
8
9
  #elif defined(STM32F10x) || defined(STM32F4XX) || defined __MINGW64__ \
10
        || defined __MING32__ || defined __linux__
11
        #define PGMSPACE_EMULATION 1
12
13
    #else
14
        #error "undefined platform"
15
16
    #endif
17
18
19
    #if PGMSPACE_EMULATION
20
    #define PROGMEM
21
    #define pgm_read_byte(a) (*(a))
22
    #define pgm_read_word(a) (*(a))
23
    #define pgm_read_pointer(a) (*(a))
24
    #define constflash const
25
    #define PSTR(a) (a)
26
27
    #define strlen_P strlen
28
    #define strncpy_P strncpy
29
30
    #define vsnprintf_P vsnprintf
31
    #define printf_P printf
32
    #define fprintf_P fprintf
33
    #define fputs_P fputs
34
35
        // snprintf_P sollte wegen eines Fehlers in einer AVR-GCC-Version nicht verwendet
36
        // werden. Als Workaround wird die Funktion wasnprintf_P eingefuehrt.
37
    #define snprintf_P 1 // Fuehrt zu einem Fehler bei einem Build mit der Funktion
38
                         // snprintf_P()
39
40
    // Workaround-snprintf-Funktion
41
    #define wasnprintf_P snprintf
42
43
  #endif
44
#endif // PGMSPACE_H

(Vor dem Edit stand hier nur eine "Prinzip-Variante")

: Bearbeitet durch User
von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

D a v i d K. schrieb:
> #ifdef GCC
>     #define __flash ?
>     #define PROGMEM ??
> #endif

Hier musst Du nur die Fragezeichen entfernen, dann wird das #define 
durch einen leeren String ersetzt.

Allerdings: Ist "GCC" bei Verwendung des AVR-GCC ganz sicher nicht 
definiert?

: Bearbeitet durch User
von Harry L. (mysth)


Lesenswert?


von Oliver S. (oliverso)


Lesenswert?

Rufus Τ. F. schrieb:
> Allerdings: Ist "GCC" bei Verwendung des AVR-GCC ganz sicher nicht
> definiert?

avr-gcc ist ein gcc. Also ist das auch definiert.

Oliver

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> avr-gcc ist ein gcc. Also ist das auch definiert.

Der GCC definiert "__GNUC__" aber nicht "GCC". Da es sich um ein 
Compiler-Spezifisches Makro handelt, darf es nicht mit eventuellen 
Bezeichnern im User-Code kollidieren. Stell dir vor jemand hat dieses 
absolut korrekte und standardkonforme C-Programm verfasst:
1
int main () {
2
  int GCC = 42;
3
  return 0;
4
}
Wenn der GCC ein Makro namens "GCC" definieren würde, würde dieser 
standarkonforme Code nicht mehr funktionieren, wodurch der GCC nicht 
standardkonform wäre. Daher fängt das Makro mit 2 Unterstrichen an. 
Würde jemand ein Programm dieser Art verfassen:
1
int main () {
2
  int __GNUC__ = 42;
3
  return 0;
4
}
funktioniert es vielleicht in manchen Compilern, aber da Bezeichner mit 
2 Unterstrichen im User-Code verboten sind, ist es falsch und nicht 
standard-konform. Daher ist es ok wenn dieses Programm nicht im GCC 
funktioniert, was auch der Fall ist, da der GCC "__GNUC__" definiert.

Also: Kein Compiler wird ein Makro namens "GCC" definieren oder sonst 
irgendein compilerspezifisches Makro ohne 2 Unterstriche oder 
Unterstrich+Großbuchstabe. "__GNUC__" ist das was man will.

Siehe auch hier, es gibt noch ein paar mehr Details zu beachten:
https://sourceforge.net/p/predef/wiki/Compilers/

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


Lesenswert?

PROGMEM kannst du gern in eigenem Code definieren, aber __flash gehört 
zum implementation namespace, davon solltest du die Finger lassen.

Umschreib' das besser komplett anders, bspw.:
1
#ifdef __AVR__
2
#  define FLASHSTRING(sym, str) const char sym[] __flash = str
3
#else
4
#  define FLASHSTRING(sym, str) const char sym[] = str
5
#endif
6
7
// ...
8
FLASHSTRING(msg1, "Hello, world!\n");
9
FLASHSTRING(msg2, "Good bye!\n");

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Oliver S. schrieb:
> avr-gcc ist ein gcc. Also ist das auch definiert.

Und damit ist es hier unbrauchbar, um zwischen GCC für AVR und GCC für 
das Wirtssystem zu unterscheiden. Deshalb fragte ich danach.

Also ist
1
#ifndef __AVR__
2
    #define __flash
3
    #define PROGMEM
4
#endif

eine simple Lösung.

Jörgs Ansatz ist natürlich der bessere, erfordert aber mehr Arbeit.

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.