Forum: Compiler & IDEs Verständnisproblem bei Makro


von Tobias M. (eule)


Lesenswert?

Hallo,
bin gerade dabei ein bestehendes µC-Programm eines ATMEL-Controllers, in 
C-Code, umzuschreiben um es auf einem anderen µC laufen zu lassen. Dabei 
bin ich auf folgendes Makro gestoßen, welches mir Verständnisprobleme 
bereitet:

   #define FlashConst(s) (__extension__({static unsigned char __c[] 
PROGMEM =
   (s); &__c[0];}))

Ist jemand in der Lage mir diesen Qellcode zu erläutern?

Danke im voraus...

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


Lesenswert?

Naja, als erstes solltest du eine beispielhafte Makroersetzung
durchführen.  Nehmen wir mal an, du hast irgendwo:
1
  cp = FlashConst("Hello, world!");

dann ergibt sich daraus:
1
  cp = (__extension__({static unsigned char __c[] __attribute__((__progmem__)) = ("Hello, world!"); &__c[0];}))

Dabei hast du folgende Teile:
1
__extension__
markiert den nachfolgenden Konstrukt als eine Erweiterung (des GCC)
zum C-Standard.  Damit wird es bei -std=c89 oder -std=c99 nicht
angewarnt, weil dem Compiler explizit mitgeteilt wird, dass sich
der Entwickler darüber im Klaren ist, dass der Konstrukt nicht dem
Standard entspricht.
1
static unsigned char __c[]
eine normale statische Variable, die lokal zum soeben angelegten
Block ist.
1
__attribute__((__progmem__))
eine Sonderanweisung an den GCC, die damit deklarierte Variable statt
im SRAM des AVR im Flash-ROM unterzubringen.

Danach folgt eine gewöhnliche Initialisierung dieser Variable mit
der übergebenen Zeichenkettenkonstanten.
1
&__c[0];
Es wird die Adresse des ersten Elements der statischen Variablen
gebildet und als Ausdruck verwendet.  Da dieser Ausdruck der letzte
innerhalb des umschließenden Blocks ist, gibt der Block dessen Wert
(ähnliche der “return”-Anweisung einer Funktion) zurück, d. h. er
darf auf der rechten Seite einer Zuweisung benutzt werden.

Die Möglichkeit, dass ein Block einen Wert zurückgeben kann, ist die
eigentliche Spracherweiterung des GCC, für die einleitend das
__extension__-Schlüsselwort notwendig geworden ist.

Ob andere Compiler über ähnliche Mechanismen verfügen wie GCC hier,
lässt sich nicht ohne weiteres sagen.  Ohne C-Spracherweiterungen ist
die entsprechende Funktionalität nicht implementierbar (zumindest nicht
auf diese Weise), daher wurde dieser vergleichsweise umständliche
Konstrukt gewählt.

von Tobias M. (eule)


Lesenswert?

Ich könnte also demnach auch eine Funktion definieren, mit einem 
"unsigned char"-Array und einem Zeiger in dem die Adresse des ersten 
Elementes dieses Arrays gespeichert wird als Parameter?

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


Lesenswert?

Die Frage verstehe ich so nicht...

Erstens, nicht "unsigned char", sondern "char".  Es handelt sich um
Zeichenkettenkonstanten, und die sind per definitionem immer vom
Typ char[], nicht signed char[], auch nicht unsigned char[].

Zweitens schrieb ich doch: mir ist keine Möglichkeit bekannt, die
gleiche Funktionalität auf irgendeine Weise mit Mitteln zu erreichen,
die komplett vom C-Standard abgedeckt sind.

von Tobias M. (eule)


Lesenswert?

Tut mir leid, ich bin absoluter Anfänger im Thema µC und im 
Programmieren mit C. Mir würde es ausreichen wenn ich eine Funktion 
hätte die als Argument eine    Zeichenkette erwartet und die Adresse des 
ersten Elements dieser Kette als Rückgabewert dient.- Ich hoffe das ist 
jetzt einigermaßen verständlich.

Aber im Original-Quelltext steht
1
unsigned char
.

von Rolf Magnus (Gast)


Lesenswert?

> Mir würde es ausreichen wenn ich eine Funktion hätte die als Argument
> eine Zeichenkette erwartet und die Adresse des ersten Elements dieser
> Kette als Rückgabewert dient.

Dazu brauchst du keine Funktion. Wenn du das Array verwendest, wird 
automatisch die Adresse des ersten Elements dafür eingesetzt.

> Aber im Original-Quelltext steht
> unsigned char

Funktionieren wird's vermutlich trotzdem, aber richtig ist eben 
eigentlich nicht.

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


Lesenswert?

Rolf Magnus wrote:

> Dazu brauchst du keine Funktion. Wenn du das Array verwendest, wird
> automatisch die Adresse des ersten Elements dafür eingesetzt.

Allerdings hat der Makro im Original halt was anderes getan: er hat
den String im Flash-ROM platziert und dann dessen Adresse ermittelt.
Wenn dein Zielprozessor sowas nicht braucht, dann kannst du den
Makro wahrscheinlich durch einen Nullmakro ersetzen:
1
#if defined __AVR__
2
#  define FlashConst(s) // hier das, was du schon kennst
3
#elif defined __FOOBAR__ // Test für Zielprozessor FOOBAR
4
#  define FlashConst(s) (s)
5
#else
6
#  error "Unknown target CPU"
7
#endif

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.