Arduino - Alternativen zu bedingter Compilierung und sog. "Procedur-Variablen"

OP #6457733
Lesenswert?

Hallo allerseits,

ich beschäftige mich erst relativ kurze Zeit mit der Arduino- und 
C-Programmierung und bin auf zwei kleine - vielleicht recht naive - 
Fragen gestoßen, auf die ich bisher keine Antworten gefunden habe.

1. Bedingte Compilierung vs. boolsche Konstante.-
Da der Compiler so etwas ja entsprechend optimieren würde (hoffentlich), 
wäre doch eine Formulierung wie folgende ein vollwertiger Ersatz. 
Erscheint mir in vielen Fällen einfacher, flexibler und übersichtlicher.
1
const boolean zeigsmir = true; // auf false setzten, wenn nicht mehr benötigt
2
.
3
.
4
if (zeigsmir) Serial.println ("Da hast du es!");

Spricht da was gegen? Ein paar Versuche zeigen, dass zumindest die Werte 
für die Speicherauslastung gleich sind mit "echten" bedingten 
Programmierung mit
1
#define ZEIGSMIR

2. In Pascal habe ich früher gerne sog. Prozedurvariablen verwendet. Man 
kann damit z.B. eine Dummy-Procedur definieren und zur Laufzeit die 
entsprechende gewünschte Procedur zuweisen. So etwas kann ganze 
Bedingungs-Kaskaden mit Ifs und Cases ersetzten. Intern geht das 
natürlich mit Pointern und entspricht im Grunde den in den Untis 
automatisch eingesetzten Konzepten.
Das sollte doch eigentlich erst recht in Arduino-C funktionieren, und 
gerade bei  µC-Programmierung sinnvoll sein? Ich habe nur noch nicht 
gefunden, wie das geht - vielleicht kann mir da jemand mit einem kleinen 
Tipp / Beispiel aufs Pferdchen helfen?

MfG, OldUri
Gast #6457735
Lesenswert?

Peter B. schrieb:
> Spricht da was gegen?

Nö. Nur in manchen Fällen möchte man Code deaktivieren, welcher gar 
nicht kompilierbar wäre; das geht dann nur mit #ifdef .

Peter B. schrieb:
> Arduino-C

Arduino-C gibt es nicht. Die Arduino-IDE verwendet C++, nicht C.

Du meinst wahrscheinlich Funktionszeiger. Du kannst auch Polymorphie mit 
virtuellen Funktionen verwenden um Programme besser zu strukturieren.
OP #6457747
Lesenswert?

Danke für die schnellen Antworten!

Frage 1 ist für mich hiermit klar , die Antworten auf Frage 2 bietet mir 
zumindest die Fachbegriffe, nach denen ich suchen kann. Wenn ich nicht 
herauskriegen sollte, wie man das macht,

jo mei schrieb:
> Funktionszeiger auf eine Funktion
> seiner Wahl zeigen lassen

werde ich nochmal nachfragen.
--------------------------------------
Habe in "wikibooks.org" ein Beispiel für Funktionszeiger gefunden, das 
genau meine Kragenweite hat - tja, das war der Begriff, der mir fehlte.

Nochmals Danke
MfG
OldUri
Gast #6457795
Lesenswert?

Peter B. schrieb:
> werde ich nochmal nachfragen.

Hier ein Beispiel schnell in der Arduino IDE zusammengehackt. Die
Funktionspointer sind weder Arduino- noch Cplusplus-spezifisch.

Als Anfänger hatte ich vor vielen Jahren als zunächst mal den
Wunsch einen Satz von I/O-Funktionen schnell umzuschalten ohne
bei jedem Ausführen eine IF-Bedingung abzufragen. Das hat zum
Glück mit den Funktionspointern geklappt und hat mir einiges
an Ausführungszeit gespart.
Angehängte Dateien:
#6457836
Lesenswert?

Peter B. schrieb:
> const boolean zeigsmir = true;

Sobald das Programm aus mehrerern Objekten besteht, gibt es Ärger. Eine 
Variable darf nur in einem Objekt definiert und initialisiert werden.
In einem h-File ist nur die Deklaration einer Variablen zulässig und 
dann kann der Compiler nicht mehr erkennen, wo ein Zuweisung erfolgt. Er 
muß die Variable also zur Laufzeit auswerten, d.h. den kompletten Code 
erzeugen.

Ein Define in einem gemeinsamen h-File kann dagegen von mehreren 
Objekten zur Compilezeit ausgewertet werden.
Gast #6457841
Lesenswert?

Peter D. schrieb:
> In einem h-File ist nur die Deklaration einer Variablen zulässig und
> dann kann der Compiler nicht mehr erkennen, wo ein Zuweisung erfolgt.

Es sei denn sie ist "static".

Peter D. schrieb:
> Er
> muß die Variable also zur Laufzeit auswerten, d.h. den kompletten Code
> erzeugen.

Nur in C. Wenn man in C++ (Arduino verwendet C++) ein "static const bool 
zeigsmir = false;" in einem Header verwendet, funktioniert das alles wie 
gewünscht, ohne Laufzeit-Evaluation.
Gast #6457857
Lesenswert?

Peter D. schrieb:
> Das würde ich eher als dirty hack bezeichnen.

Dieser "Hack" ist absolut gängig.

Peter D. schrieb:
> Man müßte mal überprüfen, ob für jede dieser Variablen RAM belegt wird.

Natürlich nicht, denn schließlich werden alle "if(zeigsmir)" 
wegoptimiert, die Variable dann gar nicht mehr benutzt und dann auch 
wegoptimiert, sodass sie gar keinen RAM oder Flash belegt.
Gast #6457860
Lesenswert?

Peter D. schrieb:
> Peter B. schrieb:
>> const boolean zeigsmir = true;
>
> Sobald das Programm aus mehrerern Objekten besteht, gibt es Ärger. Eine
> Variable darf nur in einem Objekt definiert und initialisiert werden.
> In einem h-File ist nur die Deklaration einer Variablen zulässig und
> dann kann der Compiler nicht mehr erkennen, wo ein Zuweisung erfolgt. Er
> muß die Variable also zur Laufzeit auswerten, d.h. den kompletten Code
> erzeugen.
>
> Ein Define in einem gemeinsamen h-File kann dagegen von mehreren
> Objekten zur Compilezeit ausgewertet werden.

Einersetzs hast du wahr, andererseits ist define auch nicht die beste 
Lösung in der C++ Arduino Welt.

Besser:
1
constexpr bool zeigsmir {true};
Das noch mit static zu garnieren, richtet erstmal keinen Schaden an.

jo mei schrieb:
> Hier ein Beispiel schnell in der Arduino IDE zusammengehackt. Die
> Funktionspointer sind weder Arduino- noch Cplusplus-spezifisch.
1
uint16_t (* func_ptr)(void);
2
uint16_t (* func_ptr2[3])(void);

Kann man durch dieses ersetzen:
1
using FunkPtr = uint16_t (*)();
2
FunkPtr func_ptr;
3
FunkPtr func_ptr2[3];
Scheint mir etwas leichter lesbar.
#6457868
Lesenswert?

Peter D. schrieb:
> Peter B. schrieb:
>> const boolean zeigsmir = true;
>
> Sobald das Programm aus mehrerern Objekten besteht, gibt es Ärger. Eine
> Variable darf nur in einem Objekt definiert und initialisiert werden.
> In einem h-File ist nur die Deklaration einer Variablen zulässig und
> dann kann der Compiler nicht mehr erkennen, wo ein Zuweisung erfolgt. Er
> muß die Variable also zur Laufzeit auswerten, d.h. den kompletten Code
> erzeugen.
>

Es geht um die Arduino IDEm, also C++. C++ Standard dazu im Anhang zur C 
Kompatiblität [diff.basic], C.1.2 (3):

"A name of file scope that is explicitly declared const, and not 
explicitly declared extern, has internal linkage, while in C it would 
have external linkage."

Darum muß man auch kein static davor schreiben.
Gast #6457874
Lesenswert?

Arduino Fanboy D. schrieb:
> Scheint mir etwas leichter lesbar.

Die Betonung liegt hier auf "mir". Bei anderen Personen kann
das aber ganz anders ausfallen. Insbesondere ist es umständlich
bei so einer "Typdefinition" - wenn sie woanders steht - erst
nachschauen zu müssen. Ausserdem ist diese Syntax vermutlich
nicht in C (ohne ++) möglich.
Gast #6457899
Lesenswert?

jo mei schrieb:
> Ausserdem ist diese Syntax vermutlich
> nicht in C (ohne ++) möglich.

Klar!
In C++ hantiert man viel mehr mit Typen, als in C, würde ich mal 
sagen...
Da ist das Using, sozusagen die erwartete Form, welche dem Prinzip der 
geringsten Verwunderung entspricht.

Naturgemäß sieht das so manch ein C Liebhaber anders.

Der TE taucht frisch in die Arduino Welt ein, warum soll er da erst den 
C Weg lernen, wenn er doch C++ schreibt.

Beispiel:
1
// C und C++ Variante
2
  for (uint16_t i=0; i<3; i++)
3
  {
4
    func_ptr2[i]();
5
  }
6
  
7
// modernere C++ Variante (auch Arduino)
8
  for (FunkPtr p:func_ptr2) p();
Gast #6457909
Lesenswert?

Arduino Fanboy D. schrieb:
> // modernere C++ Variante (auch Arduino)
>   for (FunkPtr p:func_ptr2) p();

Das ist die übersichtlichste und einfachste Schreibweise, für
den Anfänger der C bzw C++ machen möchte, gelle?

Geht sozusagen sofort ins Ohr. Meine Bewunderung für dein
Einfühlungsvermögen.

Ich wundere mich nur warum du nicht gleich selbst ein Beispiel
für Funktionspointer gebracht hast sondern erst an meinem
hochkomplizierten Beispiel herummachen musst.
Gast #6457924
Lesenswert?

jo mei schrieb:
> Ich wundere mich nur warum du nicht gleich selbst ein Beispiel
> für Funktionspointer gebracht hast sondern erst an meinem
> hochkomplizierten Beispiel herummachen musst.

Wieso...
Deins ist doch super, als Ausgangsbasis.

jo mei schrieb:
> Das ist die übersichtlichste und einfachste Schreibweise, für
> den Anfänger der C bzw C++ machen möchte, gelle?
>
> Geht sozusagen sofort ins Ohr. Meine Bewunderung für dein
> Einfühlungsvermögen.
Nunja ...
Zumindest ist die knapper und weniger Fehlerträchtig.

Die C Variante ist natürlich auch richtig.
Birgt aber immer wieder die Gefahr, dass da ein Index/Pointer aus dem 
Ruder läuft.
Ein kleiner Tippfehler bei der Bedingung reicht dafür und es scheppert, 
ohne dass der Compiler das unbedingt melden muss.

Nein, wenn man den Index nicht noch für was anderes braucht, ist der 
"range based for loop" eindeutig die bessere Variante.

Schlechter lesbar ist er nur, wenn man ihn nicht kennt.
Aber das kann man ja ändern.
#6458053
Lesenswert?

Arduino Fanboy D. schrieb:
> // modernere C++ Variante (auch Arduino)
>   for (FunkPtr p:func_ptr2) p();

Wobei das ein recht konstruiertes Beispiel ist. Selten will man wirklich 
immer alle Funktionen nacheinander ausführen.

Ich würde wenigstens nicht initalisierte Pointer überspringen, damit man 
nicht ständig den Resetvektor ausführt:
1
  for (FunkPtr p:func_ptr2)
2
    if (p)
3
      p();
Gast #6458066
Lesenswert?

Peter D. schrieb:
> Selten will man wirklich
> immer alle Funktionen nacheinander ausführen.

Der Sinn eines Arrays von Funktionspointern liegt z.B. darin
dass man einen Befehlsinterpreter bauen kann der sehr schnell
ist da er keine länglichen Listen von IF-Bedingungen abklappern
muss.
Gast #6458071
Lesenswert?

Peter D. schrieb:
> Selten will man wirklich
> immer alle Funktionen nacheinander ausführen.
Dass man Arrays ganz durchläuft, ist eigentlich eine recht häufige 
Anwendung.
Dann ist diese Schleifenform besonders interessant.

Wenn nullptr, oder kaputte Pointer, auftreten können, hast du allerdings 
wahr.
Die  nullptr Abfrage fehlt dann aber auch in der Schleife mit Index.

1
// abhilfe
2
FunkPtr func_ptr2[] {func1,func2,func3};
Gast #6458121
Lesenswert?

Gruss

Da sind nicht nur Befehlsinterpretationen
mit möglich, auch Kompilate.
Das hat mal jemand realisiert, vor einiger
Zeit vernahm ich ihn noch bei Green Arrys.
Nebenan gibts noch das Lambda Kalkül, das währe  gefürchtet.
Und noch: (Oh) Tannenbaum, Autor eines Buches.

Mit Gruss und Top
Dirk St

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren