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
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.
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.
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
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.
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.
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.
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.
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.
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
constexprboolzeigsmir{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.
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.
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.
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'.
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]
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:
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.
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.
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
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:
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.
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.
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