Forum: Compiler & IDEs Kleine Frage zu Makros


von Christian J. (Gast)


Lesenswert?

Moin,

ich habe aktuell folgende Funktion. Diese Minifunktionen sollen aber als 
Makros verschwinden, da sie mir die Lesbarkeit des Codes erschweren und 
idealerweise sowieso Inline sein sollen. Codegröße spielt keine Rolex, 
ist genug Platz da.
1
/* Liefert das TX_DS Flag des Status Register zurück */
2
uint8_t RF_Status_TX_DS() {
3
  CSN_LOW;
4
  uint8_t stat = SPI_TransferByte(0xff);
5
    CSN_HIGH;
6
  return (stat & _BV(NRF24L01_TX_DS);
7
}

CSN_LOW und _HIGH sind selbst Makros.

Wie kriege ich es hin, dass ein Makro mit gleichem Namen den 1 oder 0 
Wert des letzten Ausdrucks liefert? Ich übergebe ja keinen Parameter wie 
x.

von Ingo L. (corrtexx)


Lesenswert?

Christian J. schrieb:
> Wie kriege ich es hin, dass ein Makro mit gleichem Namen den 1 oder 0
> Wert des letzten Ausdrucks liefert?
Lass dir den Satz mal auf der Zunge zergehen und überlege, ob du den 
Satz selbst verstehen würdest!

von Christian J. (Gast)


Lesenswert?

Diese Antwort löst nicht mein Problem.

von Ingo L. (corrtexx)


Lesenswert?

Christian J. schrieb:
> Diese Antwort löst nicht mein Problem.
Und ich verstehe nichtmal deine Frage

von Christian J. (Gast)


Lesenswert?

Ingo L. schrieb:
> Und ich verstehe nichtmal deine Frage

In Foren gehört zu den Grundregeln, dass man nur etwas sagt, wenn man 
etwas zur Lösung zu sagen hat und ansonsten schweigt.

von Stefan S. (chiefeinherjar)


Lesenswert?

Christian J. schrieb:
> Ingo L. schrieb:
>> Und ich verstehe nichtmal deine Frage
>
> In Foren gehört zu den Grundregeln, dass man nur etwas sagt, wenn man
> etwas zur Lösung zu sagen hat und ansonsten schweigt.

Also Rückfragen sind auch nicht erlaubt?
Schade. Ich wollte dich eigentlich auch gerade bitten, dein Anliegen mit 
etwas anderen Worten nochmal zu erklären und eventuell ein Beispiel zu 
zeigen, wie du es dir ungefähr vorstellst.

Aber das darf ich ja nicht, also schweige ich jetzt lieber.

von Ingo L. (corrtexx)


Lesenswert?

Christian J. schrieb:
> In Foren gehört zu den Grundregeln, dass man nur etwas sagt, wenn man
> etwas zur Lösung zu sagen hat und ansonsten schweigt.
Olle, du bist ja ein ganz Schlauer. In Foren gehört es sich sein Problem 
zu so zu schildern das das Forum was damit anfangen kann... Siehe 
https://www.mikrocontroller.net/articles/Netiquette

von g457 (Gast)


Lesenswert?

> Wie kriege ich es hin, dass ein Makro mit gleichem Namen den 1 oder 0
> Wert des letzten Ausdrucks liefert?

GCC extensions benutzen, die können das. Einfacher, sinnvoller, besser 
und überhaupt und sowieso ist aber inlining.

von Christian J. (Gast)


Lesenswert?

Ingo L. schrieb:
> Olle, du bist ja ein ganz Schlauer. In Foren gehört es sich sein Problem
> zu so zu schildern das das Forum was damit anfangen kann... Siehe

Nur weil DU etwas nicht verstehst heisst das noch lange nicht, dass das 
für das FORUM auch gilt. Und ich ändere da meine Ansichten auch nicht, 
wenn man nichts zum Thema weiss hält man den Mund. Und fängt nicht an 
mit nervtötenden Rückfragen oder "denk aml selbst nach" den TE zu 
nerven. Ich schreibe hier NICHTS rein, was ich selbst ergooglen kann.

von Ingo L. (corrtexx)


Lesenswert?

Christian J. schrieb:
> Und fängt nicht an
> mit nervtötenden Rückfragen oder "denk aml selbst nach" den TE zu
> nerven. Ich schreibe hier NICHTS rein, was ich selbst ergooglen kann.
Wer lesen kann... Ich habe weder gesagt "denk mal selber nach" noch 
"googel selber". Ich habe gesagt:
> Lass dir den Satz mal auf der Zunge zergehen und überlege, ob du den
> Satz selbst verstehen würdest!
Soll heissen:
> Und ich verstehe nichtmal deine Frage
Aber da du nichtmal das erkennen kannst, wage ich zu bezweifeln das du 
eine Suchmaschine bedienen kannst

Christian J. schrieb:
> Nur weil DU etwas nicht verstehst heisst das noch lange nicht, dass das
> für das FORUM auch gilt.
Somit kann ICH dir nicht helfen. Sag doch gleich wenn du Hilfe von 
speziellen Leuten hier suchst

: Bearbeitet durch User
von Christian J. (Gast)


Lesenswert?

@Moderator: Bitte mal diesen sinnlosen Flamewar "bereinigen", danke!

von Peter II (Gast)


Lesenswert?

Christian J. schrieb:
> Nur weil DU etwas nicht verstehst heisst das noch lange nicht, dass das
> für das FORUM auch gilt.

gilt für mich auch - mist das darf ich gar nicht schreiben.

von Ingo L. (corrtexx)


Lesenswert?

Christian J. schrieb:
> @Moderator: Bitte mal diesen sinnlosen Flamewar "bereinigen", danke!
Ich glaube du würdest ohne einen Regenschirm bei Regen durch deine Nase 
ertrinken...

von Stefan K. (stefan64)


Lesenswert?

https://stackoverflow.com/questions/2679182/have-macro-return-a-value

Wie schon oben gesagt und auch in stackoverflow erwähnt ist inline 
allerdings erheblich sinnvoller als ein Macro.

bdw ... was ist an einem Macro besser lesbar?

Ich finde die Frage von Ingo übrigens keineswegs unangebracht.

von Ingo L. (corrtexx)


Lesenswert?

Stefan K. schrieb:
> erwähnt ist inline allerdings erheblich sinnvoller als ein Macro.
Natürlich, ein Makro is reine Textersetzung, somit Code-bloat ohne ende, 
wenn das Ganze mehrmals aufgerufen wird. Gut, bei Inline kommt das Selbe 
raus...

Stefan K. schrieb:
> bdw ... was ist an einem Macro besser lesbar?
Die Frage stelle ich mir auch gerade

: Bearbeitet durch User
Beitrag #5173307 wurde von einem Moderator gelöscht.
von Der E. (rogie)


Lesenswert?

Also ich verstehe die Frage des TE auch nicht. Also muss ich den Mund 
halten, da ich ja deshalb zum Thema nix beitragen kann. :-D

von Jack (Gast)


Lesenswert?

Ingo L. schrieb:
> Die Frage stelle ich mir auch gerade

Ich glaube man muss das nicht hinterfragen. Aus dem Verhalten des 
Fragestellers kann man schließen dass etwas ganz anderes, 
nichttechnisches nicht stimmt.

Eine kurze Suche verrät übrigens, dass der Fragesteller hier seit zwei 
Jahren gerne seine (beruflichen?) Probleme lösen lässt, aber in der Zeit 
praktisch nie jemandem bei einer Frage geholfen hat. Wenn er einen 
Thread nicht selber startet stört er gerne mit einem Problem einen 
vorhanden Thread.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Christian J. schrieb:
> @Moderator: Bitte mal diesen sinnlosen Flamewar "bereinigen", danke!

Die Rückfragen der Forenteilnehmer hier sind durchaus berechtigt, und
den Flameware ist zum einen kein Flameware (wenn ich hier nicht Mod
wäre, würde ich dir jetzt zeigen, was ein echter Flameware ist), zum
anderen hast du den Verlauf Diskussion mit deiner pampigen Aussage

> Diese Antwort löst nicht mein Problem.

selber zu deinen Ungunsten beeinflusst.

Christian J. schrieb:
> Diese Minifunktionen sollen aber als Makros verschwinden, da sie mir
> die Lesbarkeit des Codes erschweren

Willst du ein Makro, oder soll genau dieses verschwinden?

> und idealerweise sowieso Inline sein sollen.

Der Code für die Funktion soll also inline generiert werden. Hast du
nachgeschaut, ob das der Compiler nicht sowieso schon macht?

> Codegröße spielt keine Rolex

Aha.

> Wie kriege ich es hin, dass ein Makro mit gleichem Namen den 1 oder 0
> Wert des letzten Ausdrucks liefert?

Soll das Makro, ähnlich einer Funktion, einen Rückgabewert liefern?

> Ich übergebe ja keinen Parameter wie x.

Was hat der Rückgabewert mit dem nicht übergebenen Parameter x zu tun?

Ich habe nach etwa viermaligem Durchlesen deiner Anfrage eine ganz
leise Ahnung, was du damit meinen könntest, aber sicher bin ich mir
keineswegs. Wenn ich meiner Ahnung richtig liege, wäre es noch
interessant zu wissen, was sich hinter den Makros CSN_LOW und CSN_HIGH
verbirgt.

Da meine Fragen dein Problem aber nicht direkt lösen, halte ich jetzt
lieber meine Klappe ;-)

von Lukas T. (tapy)


Lesenswert?

Der hat gerade ... seinen Account gelöscht, oder?
Heftig. So löst man Probleme.

von Ordner (Gast)


Lesenswert?

Lukas T. schrieb:
> Der hat gerade ... seinen Account gelöscht, oder?
> Heftig. So löst man Probleme.

Wenn das Problem das Verhalten mancher K.-Chargen im Forum ist, dann ist 
auch die einzig richtige Lösung.

von Sebastian S. (amateur)


Lesenswert?

Die Menge an Antworten und
die Menge an Rückfragen sprechen wohl eine klare Sprache!

von Christian J. (Gast)


Lesenswert?

Yalu X. schrieb:

> Christian J. schrieb:
>> @Moderator: Bitte mal diesen sinnlosen Flamewar "bereinigen", danke!
>
> Die Rückfragen der Forenteilnehmer hier sind durchaus berechtigt, und
> den Flameware ist zum einen kein Flameware (wenn ich hier nicht Mod
> wäre, würde ich dir jetzt zeigen, was ein echter Flameware ist), zum
> anderen hast du den Verlauf Diskussion mit deiner pampigen Aussage

Sorry, aber ich habe den Thread nicht mehr weiter verfolgt, da das Thema 
längst entgleist war. Zudem meinen Account, der seit 2004 durchgehend 
bestand aus Datenschutzgründen entsorgt, da geht mir einiges zu weit was 
hier "geschnüffelt" wird, das habe ich schon mehrmals beobachtet. Es 
geht ja auch ohne und mit x-beliebigen Fake-Namen, schliesslich begegnet 
man sich sowieso nie im realen Leben. Trotzdem Danke für Deine Mühe noch 
etwas Sachliches zum Thema beizutragen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian J. schrieb:
> da geht mir einiges zu weit was hier "geschnüffelt" wird, das habe ich
> schon mehrmals beobachtet.

Das ist eine ziemlich derbe Unterstellung.

von Markus F. (mfro)


Lesenswert?

Christian J. schrieb:
> Diese Minifunktionen sollen aber als
> Makros verschwinden, da sie mir die Lesbarkeit des Codes erschweren und
> idealerweise sowieso Inline sein sollen.

Natürlich lässt sich das mit Makros lösen (Hinweis: der Komma-Operator 
dürfte dabei möglicherweise hilfreich sein), aber lesbarer ist das 
bestimmt nicht.

Schneller als eine inline-Funktion ist es ganz bestimmt auch nicht.

Ich würde mich mit etwas sinnvollerem beschäftigen...

von Christian J. (Gast)


Lesenswert?

Rufus Τ. F. schrieb:

> Christian J. schrieb:
>> da geht mir einiges zu weit was hier "geschnüffelt" wird, das habe ich
>> schon mehrmals beobachtet.
>
> Das ist eine ziemlich derbe Unterstellung.

Nein, keinesfalls. Es gibt Leute und dazu gehöre ich, die gern anonym im 
Web bleiben möchten, daher nutze ich keine Realnamen. Und es ist nicht 
nur einmal passiert, dass ich e-mail bekam oder auch eine Facebook 
Anfrage, weil jemand über diese Suche meinen Realnamen in einem Stück 
Source von mir fand und dann im Netz damit auf die Suche ging. Es gibt 
hier, wie auch sonst überall ziemlich kranke Typen, die einem regelrecht 
nachstellen, wenn sie erst einmal "auf Spur  sind, namentlich zb 
Arduinoquäler, der obwohl ich ihn konsequent ignoriere seit 2-3 Jahren 
so als existiere er gar nicht immer wieder aufs Neue versucht mich zu 
provozieren, zu einer Reaktion zu bewegen. Das ist schon ziemlich krank.

von Christian J. (Gast)


Lesenswert?

Markus F. schrieb:
> Natürlich lässt sich das mit Makros lösen (Hinweis: der Komma-Operator
> dürfte dabei möglicherweise hilfreich sein), aber lesbarer ist das
> bestimmt nicht.

Mit den besagten gcc Extension __inline attribute((... geht das auch so 
ganz gut. Nur macht eine Fülle von Minifunktionen Code unübersichtlich. 
Ich ziehe ein IsDataInBuffer() halt einem kryptischen Ausdruck vor. Nur 
habe ich diese Extensions bisher nicht verwendet. Und einem Makro einen 
Rückgabewert zu verpassen geht halt über (x), indem man x einen Wert zu 
weist.  #define ADD(a,b) {a+b} hat als "Rückgabewert"(hust...) a+b, auch 
wenn es nur ein Textersatz ist.

von Markus F. (mfro)


Lesenswert?

Christian J. schrieb:
> #define ADD(a,b) {a+b} hat als "Rückgabewert"(hust...) a+b, auch

Yo, und der ist auch noch falsch, wenn man z.B. mit

ADD(x & 0xf, 4)

aufruft (Operator-Precedence). Makros haben ihre Berechtigung. Aber 
längst nicht überall und insbesondere nicht dort, wo es bessere Lösungen 
gibt.

von Dr. Sommer (Gast)


Lesenswert?

Christian J. schrieb:
> Nur macht eine Fülle von Minifunktionen Code unübersichtlich.
Wieso ist denn eine Fülle an Mini-Makros besser?! Es ist generell 
Konsens, dass viele kleine Funktionen wenigen großen Funktionen zu 
bevorzugen sind. Eine Funktion macht genau eine Sache, das macht sie 
leicht verständlich, wartbar und kombinierbar. Man kann seine Funktionen 
ja in einzelne Dateien gruppieren, oder in C++ in einzelne Klassen & 
Namespaces.
Klassisches Beispiel: In POSIX gibt es kleine Funktionen fork(), exec(), 
dup2() mit denen man einen Prozess erstellen und stdout/in/err umleiten 
kann. Die sind viel übersichtlicher als die eine Win32-Riesen-Funktion 
CreateProcess, welche über mehrere große Parameter-Structs das gleiche 
macht.

von Peter II (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Klassisches Beispiel: In POSIX gibt es kleine Funktionen fork(), exec(),
> dup2() mit denen man einen Prozess erstellen und stdout/in/err umleiten
> kann. Die sind viel übersichtlicher als die eine Win32-Riesen-Funktion
> CreateProcess, welche über mehrere große Parameter-Structs das gleiche
> macht.

blödes Beispiel. Um die gleiche Funktionalität wie CreateProcess zu 
erreichen muss man viel mehr code schreiben.

von Dr. Sommer (Gast)


Lesenswert?

Peter II schrieb:
> blödes Beispiel. Um die gleiche Funktionalität wie CreateProcess zu
> erreichen muss man viel mehr code schreiben.
Nicht wenn man die dutzenden Zeilen zur Initialisierung der 
Parameter-structs mitzählt. Ich beziehe mich hier auch nur auf die 
stdout/in/err Funktionalität, die ganzen weiteren Parameter hab ich mal 
außer Acht gelassen. Ich will hier auch nicht gegen Windows flamen, das 
Win32-API hat auch Vorteile gegenüber beispielsweise dem von Linux.

von Jüntha (Gast)


Lesenswert?

Christian J. schrieb:
> ....meinen Realnamen in einem Stück
> Source von mir fand und dann im Netz damit auf die Suche ging. Es gibt
> hier, wie auch sonst überall ziemlich kranke Typen, die einem regelrecht
> nachstellen, wenn sie erst einmal "auf Spur  sind, namentlich zb
> Arduinoquäler, der obwohl ich ihn konsequent ignoriere seit 2-3 Jahren
> so als existiere er gar nicht immer wieder aufs Neue versucht mich zu
> provozieren, zu einer Reaktion zu bewegen. Das ist schon ziemlich krank.

Da gebe ich Dir Recht und sage Dir zum Trost: Da bist Du nicht der 
Einzige, der sich mit solchen kranken Typen auseinanderzusetzen hatte.

von L. N. (derneumann)


Lesenswert?

Christian J. schrieb:
> Nein, keinesfalls. Es gibt Leute und dazu gehöre ich, die gern anonym im
> Web bleiben möchten, daher nutze ich keine Realnamen. Und es ist nicht
> nur einmal passiert, dass ich e-mail bekam oder auch eine Facebook
> Anfrage, weil jemand über diese Suche meinen Realnamen in einem Stück
> Source von mir fand und dann im Netz damit auf die Suche ging. Es gibt
> hier, wie auch sonst überall ziemlich kranke Typen, die einem regelrecht
> nachstellen, wenn sie erst einmal "auf Spur  sind, namentlich zb
> Arduinoquäler, der obwohl ich ihn konsequent ignoriere seit 2-3 Jahren
> so als existiere er gar nicht immer wieder aufs Neue versucht mich zu
> provozieren, zu einer Reaktion zu bewegen. Das ist schon ziemlich krank.

Anhand dessen und deinem bisherigen Verhalten in diesem Thread schließe 
ich, dass du dich wohl öfter mit anderen in die Haare kriegst. Scheinst 
ja ein echt feiner Kerl und Sympathieträger zu sein. Was für herzensgute 
Menschen hier unterwegs sind, dass überhaupt versucht wird dir zu 
helfen.

von Marc (Gast)


Lesenswert?

Ich verstehe nach mehrmaligen Lesen des Threads immer noch nicht um was 
es geht. Kann mich jemand aufklären?

von Christian J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Wieso ist denn eine Fülle an Mini-Makros besser?! Es ist generell
> Konsens, dass viele kleine Funktionen wenigen großen Funktionen zu
> bevorzugen sind.

Na schau mal, heri drin steckt alles,was der User konfigurieren muss. 
Ist der ChanFat Code. Ich finde das sehr praktisch. Ok, vermutlich eine 
Debatte um den heissen brei, weil es keinen kompilierten Nutzen bringt 
aber wie ich finde schon einen Gewinn an Ästetik.
1
#define SPI_CH  1  /* SPI channel to use = 1: SPI1, 11: SPI1/remap, 2: SPI2 */
2
3
#define FCLK_SLOW() { SPIx_CR1 = (SPIx_CR1 & ~0x38) | 0x28; }  /* Set SCLK = PCLK / 64 */
4
#define FCLK_FAST() { SPIx_CR1 = (SPIx_CR1 & ~0x38) | 0x00; }  /* Set SCLK = PCLK / 2 */
5
6
#if SPI_CH == 1  /* PA4:MMC_CS, PA5:MMC_SCLK, PA6:MMC_DO, PA7:MMC_DI, PC4:MMC_CD */
7
#define CS_HIGH()  GPIOA_BSRR = _BV(4)
8
#define CS_LOW()  GPIOA_BSRR = _BV(4+16)
9
#define  MMC_CD    !(GPIOC_IDR & _BV(4))  /* Card detect (yes:true, no:false, default:true) */
10
#define  MMC_WP    0 /* Write protected (yes:true, no:false, default:false) */
11
#define SPIx_CR1  SPI1_CR1
12
#define SPIx_SR    SPI1_SR
13
#define SPIx_DR    SPI1_DR
14
#define  SPIxENABLE() {\
15
  __enable_peripheral(SPI1EN);\
16
  __enable_peripheral(IOPAEN);\
17
  __enable_peripheral(IOPCEN);\
18
  __gpio_conf_bit(GPIOA, 4, OUT_PP);            /* PA4: MMC_CS */\
19
  __gpio_conf_bit(GPIOA, 5, ALT_PP);            /* PA5: MMC_SCLK */\
20
  GPIOA_BSRR = _BV(6); __gpio_conf_bit(GPIOA, 6, IN_PUL); /* PA6: MMC_DO with pull-up */\
21
  __gpio_conf_bit(GPIOA, 7, ALT_PP);            /* PA7: MMC_DI */\
22
  GPIOC_BSRR = _BV(4); __gpio_conf_bit(GPIOC, 4, IN_PUL);  /* PC4: MMC_CD with pull-up */\
23
  SPIx_CR1 = _BV(9)|_BV(8)|_BV(6)|_BV(2);          /* Enable SPI1 */\
24
}

von Dr. Sommer (Gast)


Lesenswert?

Und das hier ist so viel hässlicher?
1
#define SPI_CH  1  /* SPI channel to use = 1: SPI1, 11: SPI1/remap, 2: SPI2 */
2
3
inline void FCLK_SLOW() { SPIx_CR1 = (SPIx_CR1 & ~0x38) | 0x28; }  /* Set SCLK = PCLK / 64 */
4
inline void FCLK_FAST() { SPIx_CR1 = (SPIx_CR1 & ~0x38) | 0x00; }  /* Set SCLK = PCLK / 2 */
5
6
#if SPI_CH == 1  /* PA4:MMC_CS, PA5:MMC_SCLK, PA6:MMC_DO, PA7:MMC_DI, PC4:MMC_CD */
7
inline void CS_HIGH() { GPIOA_BSRR = _BV(4); }
8
inline void CS_LOW()  { GPIOA_BSRR = _BV(4+16); }
9
inline bool MMC_CD()  { return  !(GPIOC_IDR & _BV(4)); }  /* Card detect (yes:true, no:false, default:true) */
10
static const bool MMC_WP = false; /* Write protected (yes:true, no:false, default:false) */
11
#define SPIx_CR1  SPI1_CR1
12
#define SPIx_SR    SPI1_SR
13
#define SPIx_DR    SPI1_DR
14
inline void SPIxENABLE() {
15
  __enable_peripheral(SPI1EN);
16
  __enable_peripheral(IOPAEN);
17
  __enable_peripheral(IOPCEN);
18
  __gpio_conf_bit(GPIOA, 4, OUT_PP);            /* PA4: MMC_CS */\
19
  __gpio_conf_bit(GPIOA, 5, ALT_PP);            /* PA5: MMC_SCLK */\
20
  GPIOA_BSRR = _BV(6); __gpio_conf_bit(GPIOA, 6, IN_PUL); /* PA6: MMC_DO with pull-up */\
21
  __gpio_conf_bit(GPIOA, 7, ALT_PP);            /* PA7: MMC_DI */\
22
  GPIOC_BSRR = _BV(4); __gpio_conf_bit(GPIOC, 4, IN_PUL);  /* PC4: MMC_CD with pull-up */\
23
  SPIx_CR1 = _BV(9)|_BV(8)|_BV(6)|_BV(2);          /* Enable SPI1 */\
24
}

Ich finde das im Gegenteil besser lesbar, weil so klar ist dass bspw. 
CS_HIGH() wie eine Funktion behandelt wird und da nicht irgendeine 
weitere Makro-Syntax-Zauberei bei der Nutzung folgt.

Außerdem ist deine Anwendung von Code-Blöcken mit { } im Makro 
problematisch: Du solltest "do { ... } while (0)" verwenden, siehe z.B. 
hier:
https://stackoverflow.com/a/154138

Zudem sind Namen, die mit 2 Unterstrichen beginnen, wie 
"__gpio_conf_bit", der C(++)-Standard-Library sowie dem Compiler 
vorbehalten und sollten daher in User-Code nicht vorkommen.

von Dr. Sommer (Gast)


Lesenswert?

PS: Letzteres gilt auch für Unterstrich + Großbuchstabe, also auch für 
"_BV". Beim AVR-GCC ist das Teil der C-Library, also korrekt (da muss 
es sogar so sein, denn einfach nur "BV" ist ja vom C-Standard nicht 
zugewiesen und muss daher dem User als Bezeichner zur Verfügung stehen). 
Wenn du aber "_BV" selbst im Code definierst, ist das verboten und kann 
in zukünftigen Compiler/Library-Versionen zu Kollisionen führen.

von Christian J. (Gast)


Lesenswert?

Dr. Sommer schrieb:

> Außerdem ist deine Anwendung von Code-Blöcken mit { } im Makro
> problematisch: Du solltest "do { ... } while (0)" verwenden, siehe z.B.
> hier:
> https://stackoverflow.com/a/154138

Danke für den Link! Sehr aufschlussreich, wusste ich auch noch nicht!

von Marc (Gast)


Lesenswert?

Danke jetzt hab ich`s kapierT: RF_Status_TX_DS() soll mit Makro ersetzt 
werden.

Das wuerde ich nur machen, wenn es signifikante 
Geschwindigkeitsveraenderungen bringen würde. Hast du es mal gemessen?

Nachteil von Makros ist auch, dass kein Debug Breakpunkt in die Funktion 
gesetzt werden kann.

von Dr. Sommer (Gast)


Lesenswert?

Marc schrieb:
> Das wuerde ich nur machen, wenn es signifikante
> Geschwindigkeitsveraenderungen bringen würde. Hast du es mal gemessen?
Gegenüber einer inline-Funktions bringt es sicherlich keinen 
Geschwindigkeitsvorteil. Falls der Compiler sich sträubt, zwingt man ihn 
mit "inline __attribute__((always_inline))" dazu, wie ja auch schon 
gesagt wurde.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

Marc schrieb:
> Das wuerde ich nur machen, wenn es signifikante
> Geschwindigkeitsveraenderungen bringen würde. Hast du es mal gemessen?

Hi,

ich versuche diese Lib, an der ich schon seit Monaten herum schraube, um 
sie immer besser zu machen weiter zu optimieren. Und dazu will ich jede 
Abfrage eines Bits etc in einer leicht zu benutzende Funktion packen, 
die die Hardware maximal abstrahiert. Es bringt kompiliert nichts, 
erleichtert mir aber die Benutzung der Lib für die darüber liegende 
Schicht.

von Peter D. (peda)


Lesenswert?

Christian J. schrieb:
> Wie kriege ich es hin, dass ein Makro mit gleichem Namen den 1 oder 0
> Wert des letzten Ausdrucks liefert?

Ich weiß nicht, was es daran zu mäkeln gibt, die Frage ist klar und 
eindeutig.
Und zumindest für den GCC gibt es eine Lösung. Der Returnwert eines 
Macros ist der letzte Ausdruck:
1
#define foo( )                                                          \
2
({                                                                      \
3
  uint8_t i = 0;                                                        \
4
/* some code */                                                         \
5
  i;                            /* return value of Macro */             \
6
})

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


Lesenswert?

Peter D. schrieb:
> Der Returnwert eines Macros

Korrektur: ein Makro hat keinen „Returnwert“.  Dies ist eine
GCC-Erweiterung, mit der ein Block (in geschweiften Klammern) einen
Wert haben kann, sodass man ihn als Teil eines Ausdrucks benutzen
kann.

Dass dieses Feature natürlich vorrangig dafür sinnvoll ist, dass man
einen Makro so bauen kann, dass er wie ein Wert benutzbar ist, ist
klar, aber trotzdem ist der Makro selbst nach wie vor nur eine reine
Textersetzung, sonst nichts.  Damit kann er keinen Rückgabewert haben.

von Anon Y. (avion23)


Lesenswert?

Christian J. schrieb:
> Und dazu will ich jede
> Abfrage eines Bits etc in einer leicht zu benutzende Funktion packen,
> die die Hardware maximal abstrahiert

Und genau das ist das Problem. Du beschreibst dein Makro selbst als 
Funktion. Wenn du eine Funktion willst, dann nimm auch eine.

Mit dem Makro fudelst du dich an dem Compiler vorbei. Der Code kann so 
nicht vom Compiler überprüft werden. Praktisch, weil man die Warnings 
dann nicht einmal ignorieren muss. Du, und später der Anwender, sehen 
nicht einmal den selben Code wie der Compiler!

Nimm Funktionen. Makros sind ein archaischer Nebenkrieg in einer 
weiteren Programmiersprache, die von kaum jemanden beherrscht wird.

von Chris J. (Gast)


Angehängte Dateien:

Lesenswert?

Peter D. schrieb:

> Ich weiß nicht, was es daran zu mäkeln gibt, die Frage ist klar und
> eindeutig.
> Und zumindest für den GCC gibt es eine Lösung. Der Returnwert eines
> Macros ist der letzte Ausdruck:#define foo( )
> \
> ({
> \
>   uint8_t i = 0;
> \
> /* some code */
> \
>   i;                            /* return value of Macro */
> \
> })

Das habe ich inzwischen auch schon heraus gefunden und sparsam 
verwendet. Es bringt nicht wirklich etwas, obwohl es echte Freaks gibt, 
die Makros schreiben wie andere Romane. Die dicken Fehler kommen aber 
mit den Datentypen.

Peter, wo ich Dich grad an der Strippe habe...... was ist eine 
akzeptierte Methode um in C, nicht C++, wo das einfacher ist. 
Zahlenwerte an eine Grafikfunktion zu übergeben?

Ich habe ein Histogramm geschrieben, was beschriftet ist. Aber bisher 4 
einzelne Routine für jeden Wert: Druck, Temperatur, Feuchte, 
Außentemperatur usw. Lag nahe.

Jetzt möchte ich eine Funktion haben, statt vier, der ich die Werte 
übermitteln kann. Das sind:

Position X,Y
Beschriftung
Minimaler Wert der Historie
Maximaler Wert der Historie
Aktueller Wert
Mittelwert
Mittelwertbeschriftung

zusätzlich die Daten: Zeiger auf 144 Werte, von denen aber nicht 
zwingend jeder auch vorhanden sein muss. Lücken sind erlaubt Darüber 
gibt ein Bit Auskunft, 0 oder 1.

Das wird alles miteinander verrechnet, so dass sich ein maßstabsgetreues 
Bild ergibt, egal wie gross oder klein die Werte sind, die werden intern 
normiert.

Ich kenne nur Parameterlisten aber die wären mir hier echt zu lang. 
Zudem müssen nicht alle Werte immer neu geschrieben werden für jedes 
Diagramm, manches ist gleich wie die Position.

Gibt es was Bewährtes`?

von Stefan K. (stefan64)


Lesenswert?

Dasfür würde ich einen Pointer auf zwei struct verwenden. Pack diese 
Werte
  Position X,Y
  Beschriftung
  Mittelwertbeschriftung
alle in ein struct, für jedes Histogramm eines. Diese Werte sind 
konstant, die struct kann also ins Flash, und Du übergibst Deiner 
Funktion einen ptr auf eine Flash-struct.

Diese Werte
  Minimaler Wert der Historie
  Maximaler Wert der Historie
  Aktueller Wert
  Mittelwert
packst Du in eine zweite struct, die im RAM liegt.

Der Vorteil bei den structs ist nicht nur, dass Du keine ewig langen 
Parameterübergaben hast. Du kannst auch sehr einfach zusätzliche Werte 
in die structs einbauen, wenn siespäter benötigt werden, ohne überall 
den Funktionskopf zu ändern.

Die Daten werden als ptr auf ein Array übergeben.

Gruß, Stefan

von A. S. (Gast)


Lesenswert?

Wenn die Information beim Aufrufer ist (und bleibt), dann pflegt der ein 
Feld mit den Daten und übergibt nur einen Pointer (oder 2).

Wenn die Information nicht beim Aufrufer bleibt, also mit Aufruf der 
Funktion mal diese, mal jene Info beigestuert wird und die Daten in der 
Funktion bleiben (dort gekapselt sind), dann musst Du kennzeichnen, 
welche Informationen überschrieben werden sollen. Bei nur einer Funktion 
gibt es u.a. folgende Mechnismen:

a) Übergabe der Daten mithilfe von Pointern, wobei die Pointer 0 sein 
können
b) Gültigkeitsinformationen in den Daten (valid-Bit)
c) parallele Gültigkeitsinfo
d) Parameter- und Kommandokonzepte (verschiedene Kommandos, z.B. setze 
Parameter 27 und interpretiere den obligatorischen void-pointer als 
pointer auf einen Typ Y)
e) Globaler Speicher
f) festgelegte Reichenfolge.

ich habe alle Methoden schon sinnvoll angewendet gesehen, leider einige 
auch völlig chaotisch (Write-Only-Code).

In den meisten Fällen ist "nur eine Funktion" unsinnig.

von Chris J. (Gast)


Lesenswert?

Moin,

klingt gut, so werde ich es machen. Die Messwerte liegen ja schon in 
einem großen Struct und auch alle daraus abgeleiteten Werte. Allerdings 
kann ich diesen Struct nicht einfach übergeben, da es ja verschiedene 
Variablen sind, die die Werte enthalten. Also müssen die erst umkopiert 
werden. Ich werde dann Grafik/Beschriftung und Daten voneinander 
trennen. Strings sind mir in C zwar etwas ungewohnt aber Einarbeitung 
tut not.

struct info {
char* text;      // oder char text[20] ?
....
}

wird wohl mit *info.text = "Hallo Welt";

zu füttern sein, wobei ich nicht weiss, wo das "Hallo Welt" dann steht, 
im Ram oder im Rom... oder im Initializer nach dem Startup des Codes. 
Aber eines nach dem anderen....

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> wird wohl mit *info.text = "Hallo Welt";
>
> zu füttern sein, wobei ich nicht weiss, wo das "Hallo Welt" dann steht,
> im Ram oder im Rom. Aber eines nach dem anderen...
String-Literale sollten normalerweise im ROM liegen (siehe 
Linkerscript). Dazu muss "text" aber als "const char*" definiert sein, 
sonst gibts da eine Warnung/Fehler.

von Chris J. (Gast)


Lesenswert?

Dr. Sommer schrieb:
> String-Literale sollten normalerweise im ROM liegen

Naja, die liegen erstmal alle im ROM. Nur werden die dann beim Start von 
dort aus auch auf RAM Plätze kopiert imm Zuge der Initialisierung der 
globalen Variablen. Ich gucke da sicherheitshalber immer nach im .map 
File später.

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


Lesenswert?

Dr. Sommer schrieb:
> String-Literale sollten normalerweise im ROM liegen (siehe
> Linkerscript).

Hängt von der Architektur ab.   Beim AVR bspw. liegen sie nicht im
ROM, da dieser mit völlig anderen Befehlen angesprochen werden muss
als ein regulärer char *.  Damit könnte man ein Stringliteral dann
nicht mehr an Funktionen wie strcmp() übergeben, wenn es im Flash
abgelegt ist, denn strcmp() muss genauso damit klarkommen, dass
ein normales char-Array per Zeiger übergeben wird.

> Dazu muss "text" aber als "const char*" definiert sein,
> sonst gibts da eine Warnung/Fehler.

Das wiederum muss man ohnehin tun, denn der Standard überlässt es
der Implementierung (also dem Compiler), ob er Stringliterale in einem
nicht beschreibbaren Speicher ablegt oder nicht.  Zeiger auf solche
müssen daher stets so behandelt werden, als wären sie im ROM.

von Dr. Sommer (Gast)


Lesenswert?

Chris J. schrieb:
> Nur werden die dann beim Start von
> dort aus auch auf RAM Plätze kopiert imm Zuge der Initialisierung der
> globalen Variablen.
Kommt drauf an ob die globale Variable ein Array oder ein Pointer ist. 
Ich seh hier gar keine globale Variable, sondern nur irgendeinen Pointer 
auf das String-Literal. Da wird gar nix kopiert. Auch bei einem globalen 
'const char* x = "asdf"; ' wird nur der Pointer-Wert vom ROM in den RAM 
kopiert (falls nicht sowieso wegoptimiert). Der String selbst wird nur 
bei einem 'char x [] = "asdf";' tatsächlich kopiert.

Jörg W. schrieb:
> Hängt von der Architektur ab.   Beim AVR bspw. liegen sie nicht im
> ROM, da dieser mit völlig anderen Befehlen angesprochen werden muss
> als ein regulärer char *.
Ich weiß. AVR ist auch eine komische Architektur. Der Chris arbeitet 
aber mit STM32.

Jörg W. schrieb:
> Das wiederum muss man ohnehin tun
Ja.

von Chris J. (Gast)


Lesenswert?

Man kann auch eigene Regions definieren und sie da mit 
_attribute(section.... ö.ä. hinein zu legen. Habe ich auch schon gemacht 
mit dem Backup RAM dews F429. Das wurde direkt beim Flashen auch dann 
genau dahin kopiert.

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


Lesenswert?

Dr. Sommer schrieb:

> Ich weiß. AVR ist auch eine komische Architektur.

Logische Folge, wenn man eine Harvard-Architektur mit einem
16-bit-Adressraum betreiben möchte und dabei jeweils 2 x 64 KiB
(beim instruction memory sogar 128 KiB) adressieren können möchte.

Gab's schon bei der PDP-11. :-)

Der MSP430 hat beide in einen Adressraum vereinigt, sodass die
Fummelei mit irgendwelchen Adressierungsklimmzügen schon deutlich
eher beginnt als beim AVR.

> Der Chris arbeitet
> aber mit STM32.

Steht nirgends im Thread, ich hatte extra gesucht.

von Dr. Sommer (Gast)


Lesenswert?

Jörg W. schrieb:
> Gab's schon bei der PDP-11. :-)
Dann sollten die Probleme ja bekannt sein :-P

Jörg W. schrieb:
> Steht nirgends im Thread, ich hatte extra gesucht.
Aber in seinen 5879321 weiteren Threads...

von Chris J. (Gast)


Lesenswert?

Stefan K. schrieb:

> Die Daten werden als ptr auf ein Array übergeben.

Hmmm..... der Datenstruct sieht so aus:
1
/* --- Die Datenhistorie ----- */
2
typedef struct {
3
        float    Pressure;                 // 4: History Druck[id_data]
4
        uint8_t  Ext_Feuchte;              // 4: History Feuchte Aussen[id_data]
5
                 Ext_Temperature;          // 4: History Aussentemperatur[id_data]
6
        _Bool    f_data_valid;
7
} __attribute__((packed)) volatile hist_data_t;
8
9
hist_data_t histdata[HISTORY_MAX_IDX+1]; // Daten Historie

Die Grafikroutine habe ich inzwischen auf eine einzige geschrumpft, noch 
nicht ganz fertig. Sie soll auf alle diese Datentypen passen, wobei es 
optisch schon einen Unterschied macht, ob man da mit float oder int 
arbeitet, es sieht softer aus, int erzeugt Treppchen. Der Druck muss 
also float sein, alles andere geht mit int.

Wie würde man da eine Universallösung erzeugen? Mit unions?

union value_t {
    float f _val;
    uint8_t  i_val;
}

Die Grafikroutine muss ja auch wissen welcher Wert dargestellt werden 
soll, ein data->Ext_Temperature geht nicht. Den Array vorher umkopieren 
finde ich zu aufwendig.

void DrawUniversal(struct* Grafikinfos, struct* Texte und Grenzwerte, 
void* Datensatz)

?

von Markus F. (mfro)


Lesenswert?

Chris J. schrieb:
> /* --- Die Datenhistorie ----- */
> typedef struct {
>         float    Pressure;                 // 4: History Druck[id_data]
>         uint8_t  Ext_Feuchte;              // 4: History Feuchte
> Aussen[id_data]
>                  Ext_Temperature;          // 4: History
> Aussentemperatur[id_data]
>         _Bool    f_data_valid;
> } __attribute__((packed)) volatile hist_data_t;

was macht das volatile da?

von Chris J. (Gast)


Lesenswert?

Markus F. schrieb:
> was macht das volatile da?

Variablen, die in Ints verwenden werden bezeichne ich so, da ich nicht 
sicher bin, ob jede globale Variable volatile ist. Und wenn man es da 
nicht hinschreibt meckert der GCC an anderer Stelle, nämlich bei extern 
volatile ...

Und bevor noch ein anderer fragt, warum da __attribute__((packed)) 
steht: Ich tausche Daten per Funk mit einem 8 Bit Arduino aus, der hat 
andere Datenbreiten, die sich nur so angleichen lassen.

von Markus F. (mfro)


Lesenswert?

Chris J. schrieb:
> Variablen, die in Ints verwenden werden bezeichne ich so, da ich nicht
> sicher bin, ob jede globale Variable volatile ist. Und wenn man es da
> nicht hinschreibt meckert der GCC an anderer Stelle, nämlich bei extern
> volatile ...

Uiuiui...

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.