Für wen ist dieser Artikel gedacht?
In einfachen Arduino-Sketches ist es eigentlich egal, wie man seine Konstanten definiert, wichtig ist zunächst nur Konsistenz. Wenn man jedoch auch etwas professionelleren Code schreiben möchte ist es gut, die Vor- und Nachteile der verschiedenen Optionen zu kennen.
Arduino-Sketches sind C++-Code, welcher um Arduino-spezifische Funktionen erweitert wurde. Sämtliche C++(11)-Sprachfeatures sind im Code erlaubt. Daher gibt es oft viele Wege, einen bestimmten Effekt zu erzielen. Je nach Anwendungsfall gibt es dann manchmal idiomatische und nicht-idiomatische Wege. Dieser Artikel behandelt drei verschiedene Möglichkeiten, konstante Werte im Code zu definieren und zu verwenden.
#define LED_PIN 13 #define DELAY_TIME 500 void setup() { pinMode(LED_PIN, OUTPUT); } void loop() { digitalWrite(LED_PIN, HIGH); delay(DELAY_TIME); digitalWrite(LED_PIN, LOW); delay(2 * DELAY_TIME); }
#define ist eine Präprozessor-Anweisung. Alle nachfolgenden Verwendungen von LED_PIN werden vor dem Kompilieren durch 13 ersetzt.
#undef später im Programm wieder zurücknehmen und neu definieren. Die Konstante hätte dann im ganze Programm nicht überall denselben Wert. Klar kann man sich sagen, dass man das einfach nicht macht, aber sich solch ein Regelwerk aufzusetzen und dann womöglich im Team noch durchzusetzen ist immer eher suboptimal. Es ist immer besser, wenn man so programmiert, dass schon der Compiler unsinnigen Code erkennt.#define DELAY_TIME 400 + 100 schreiben, was dann später im Programm zu nicht sofort offensichtlichen Fehlern führt (2 * 400 + 100 ist definitiv nicht dasselbe wie 2 * 500). Man kann in #defines auch Code verstecken der bei jeder Verwendung ausgeführt wird, diese Möglichkeiten verleiten oft zu schwer lesbarem Code.const int led_pin { 13 }; void setup() { pinMode(led_pin, OUTPUT); } void loop() { digitalWrite(led_pin, HIGH); delay(500); digitalWrite(led_pin, LOW); delay(500); }
const int led_pin { 13 }; ???
Diese Schreibweise nennt sich C++ uniform initialization. Sie ist fast immer besser als led_pin = 13, weil C++ auch folgenden Code erlauben würde:
const int led_pin = 13.5;
Das ist natürlich definitiv falsch. Daher gibt es seit C++11 die erstgenannte Schreibweise, bei der kein implizites type-narrowing vorgenommen wird.
const int led_pin { 13.5 };
gibt nämlich einen Kompilierfehler.
const weg-casten, aber das betrachten wir hier nicht)constexpr int led_pin { 13 }; constexpr int delay_time { 500 }; void setup() { pinMode(led_pin, OUTPUT); } void loop() { digitalWrite(led_pin, HIGH); delay(delay_time); digitalWrite(led_pin, LOW); delay(2 * delay_time); }
constexpr vereint die Vorteile der beiden vorherigen Optionen.
constexpr int delay_time { 400 + 100 }; schreiben und es funktioniert trotzdem immer noch alles wie erwartet, da der Compiler die Anweisung zur Compilezeit auswertetconstexpr nicht als Schlüsselwort
Man kann sogar einige Funktionen constexpr machen, um diese schon zur Compilezeit auszuwerten, darauf gehe ich hier aber jetzt nicht ein. Im Arduino-Kontext wird das meistens auch nicht gebraucht.