www.mikrocontroller.net

Forum: GCC Verständnisproblem bei Makro

Autor: Tobias M. (eule)
Datum: 03.05.2008 16:43

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...
Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum: 03.05.2008 17:21

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

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

Dabei hast du folgende Teile:
__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.
static unsigned char __c[]
eine normale statische Variable, die lokal zum soeben angelegten
Block ist.
__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.
&__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.
Autor: Tobias M. (eule)
Datum: 03.05.2008 19:49

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?
Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum: 03.05.2008 22:25

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.
Autor: Tobias M. (eule)
Datum: 04.05.2008 12:31

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
unsigned char
.
Autor: Rolf Magnus (Gast)
Datum: 04.05.2008 12:40

> 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.
Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum: 04.05.2008 19:37

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:
#if defined __AVR__
#  define FlashConst(s) // hier das, was du schon kennst
#elif defined __FOOBAR__ // Test für Zielprozessor FOOBAR
#  define FlashConst(s) (s)
#else
#  error "Unknown target CPU"
#endif

Antwort schreiben

Die Angabe einer Email-Adresse ist freiwillig. Wenn Sie automatisch per Email über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Suchfunktion und Betreffsuche benutzen - vielleicht gibt es schon einen ähnlichen Beitrag
  • Aussagekräftigen Betreff wählen
  • Im Betreff angeben um welchen Controllertyp es geht (AVR, PIC, ...)
  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang
  • JPEG-Dateien (.jpg) nur für Fotos verwenden, Schaltpläne, Screenshots usw. als PNG oder GIF anhängen

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [pre]vorformatierter Text (z.B. Code in anderen Sprachen)[/pre]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel






webmaster@mikrocontroller.netImpressumWerbung auf Mikrocontroller.net