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