Forum: Mikrocontroller und Digitale Elektronik Arduino - Alternativen zu bedingter Compilierung und sog. "Procedur-Variablen"


von Peter B. (olduri)


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

von Programmierer (Gast)


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.

von jo mei (Gast)


Lesenswert?

Programmierer schrieb:
> Du kannst auch Polymorphie mit
> virtuellen Funktionen verwenden um Programme besser zu strukturieren.

Man kann auch einfach einen Funktionszeiger auf eine Funktion
seiner Wahl zeigen lassen und darüber auch die Funktion
ausführen.

von Peter B. (olduri)


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

: Bearbeitet durch User
von jo mei (Gast)


Angehängte Dateien:

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.

von Peter D. (peda)


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.

von Programmierer (Gast)


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.

von Peter D. (peda)


Lesenswert?

Programmierer schrieb:
> Es sei denn sie ist "static".

Das würde ich eher als dirty hack bezeichnen. "static" sagt dem 
Compiler, lege in jedem Objekt einen neue Variable mit diesem Namen an.
Man müßte mal überprüfen, ob für jede dieser Variablen RAM belegt wird.

von Programmierer (Gast)


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.

von Einer K. (Gast)


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.

von Luther B. (luther-blissett)


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.

von jo mei (Gast)


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.

von Luther B. (luther-blissett)


Lesenswert?

Programmierer schrieb:
> 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".

Im Unterschied zu C ist in C++ hat eine "const" Deklaration immer 
internal linkage, ausser sie ist explizit 'extern'.

von Programmierer (Gast)


Lesenswert?

Luther B. schrieb:
> Im Unterschied zu C ist in C++ hat eine "const" Deklaration immer
> internal linkage, ausser sie ist explizit 'extern'.

Achja. Solche Details kann ich mir nicht merken :o]

von Einer K. (Gast)


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();

von jo mei (Gast)


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.

von Einer K. (Gast)


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.

von Peter B. (olduri)


Lesenswert?

jo mei schrieb:
> Hier ein Beispiel schnell in der Arduino IDE zusammengehackt.

Funktioniert prima. Entspricht dem bereits genannte Beispiel aus dem 
"Wikibook", ist aber vollständiger und enthebt mich der Mühe, es auf 
Arduino "umzustricken". Alles Bestens!

Grüße, OldUri

von jo mei (Gast)


Lesenswert?

Danke sehr, OldUri.

von Peter D. (peda)


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();

von jo mei (Gast)


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.

von Einer K. (Gast)


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};

von dirk (Gast)


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

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.