Variable

Wir kennen diesen Begriff aus der Mathematik. (Zitat Wikipedia: „Eine Variable ist ein Name für eine Leerstelle in einem logischen oder mathematischen Ausdruck.“) Genau solche Leerstellen können und müssen wir auch in Programmen benutzen. Denn anders als in unserem ersten Beispiel ist es meist erforderlich, dass wir auf bestimme Ereignisse oder sich verändernde Bedingungen während des Programmablaufs reagieren. Wir benötigen also Leerstellen im Speicher die wir gegebenenfalls verändern oder abfragen können. Für das anlegen und manipulieren dieser Leerstellen müssen wir uns an bestimmte Regeln halten. Denn anders als in der Mathematik, werden in einem Programm nicht nur Zahlen, sondern auch Zeichen und Zustände von Interesse sein. Zudem sollten wir uns vom Anfang an überlegen, ob diese Leerstelle dauerhaft bestehen soll, oder eventuell nur kurzzeitig interessant ist.


Typen
Als erstes machen wir uns darüber Gedanken, welchen Typ wir verwenden. Grob betrachtet kennen wir vier Typen von Variablen. Neben den Zahlen werden wir auch Zustände und Zeichen oder Zeichenketten in unseren Programmen verwenden. Für jede Anforderung gibt es unterschiedlichste Typen von Variablen. Wobei die Auswahl von verschiedenen Faktoren abhängt. Denn unsere Entscheidung beeinflusst nicht nur den Verbrauch an Speicher, sondern trägt auch viel zur Lesbarkeit eines Sketch bei und beeinflusst ganz erheblich die Geschwindigkeit des Programms. Zudem ist es oftmals erforderlich die Vorgaben einer Schnittstelle oder eines Dateityps zu berücksichtigen.
Wir werden auf dieser Seite Variablentypen grundsätzlich grün, fett und kursiv darstellen.


Zahlen
Du kennst von deinem Taschenrechner die so genannte Fließkommazahlen. Auch der Taschenrechner kann nur eine gewisse Anzahl an Stellen speichern und verarbeiten. Wenn dieser Bereich überschritten wird, lässt er die hinteren Stellen weg und speichert nur mehr, wie viele male der Wert mit 10 multipliziert oder dividiert werden muss. Dieser Typ steht Dir auch in C zur Verfügung. Solche Berechnungen belasten jedoch die CPU und den Speicher mehr als es für die meisten Aufgabe die wir lösen müssen nötig ist. Neben vielen weiteren Typen, sind die folgenden Typen in unseren Sketches gebräuchlich.

  • byte steht für ein Byte (8Bit) und kann Werte von 0 bis 255 annehmen.
    Moderne Systeme arbeiten pro Byte mit mehr als 8 Bit. 16 – 64 Bit sind hier möglich. Dieser Variablentyp sparrt demnach keinen Speicherplatz sondern vereinfacht lediglich die Verarbeitung für die CPU im Zusammenhang mit gewissen Anweisungen.
  • int steht für Integer also Ganzzahlen von -32.768 bis 32.767.
    Ein Großteil der Operationen innerhalb der Arduino- Umgebung sind für diesen Datentyp optimiert. Demnach wird er uns in weiterer Folge häufig begegnen.
  • long benutzt 4 Byte und kann Werte von −2.147.483.648 bis 2.147.483.647 verarbeiten.
    Also ganze Zahlen bis rund 2 Milliarden. Diesen Typ wirst Du zum Beispiel im Zusammenhang mit dem Zeitgeber deines MC benötigen.
  • float Fließkommazahl wie Du sie vom Taschenrechner kennst
  • Mit unsigned (beachte das Leerzeichen!) vor den Typen Integer und Long  weist du das Programm an den selben Speicherraum ohne das Vorzeichen zu berücksichtigen. Damit verdoppelt sich der positive Bereich.

Daneben kannst Du auch jeden anderen Integer- Datentyp des C++ Standards nutzen.
Die Schreibweise ist recht einfach zu erlernen.

Wenn die Variable unsigned deklariert werden soll setze ein „u“ (diesmal ohne Leerzeichen) danach scheibt man das „int“ und die Anzahl der Bits (8, 16, 32, 64). Abgeschlossen wird die Deklaration dann immer mit einem „_t“

uint8_t entspricht: byte
int16_t entspricht: int
uint32_t entspricht: unsigned long

Diese Typen haben vor allem beim auslesen und schreiben von Dateien und Verbindungen zu Hardware eine Bedeutung. Dazu wirst Du dich im Bedarfsfall mit der Dokumentation der Hardware oder des Dateityps beschäftigen müssen.


Persönliche Anmerkung:
Es gibt wahre Programmierkünstler, die bei der Deklaration jeder einzelnen Variablen den Typ so „ressourcensparend“ als irgend möglich betreiben. Wir sind oftmals gezwungen, uns an die Vorgaben eines Dateityps oder einer Hardware an zu passen. Doch wenn es geht, solltet Ihr es vermeiden, all zu viele verschiedenen Typen in einem Sketch zu nutzen. Der Code wird dadurch schwerer zu lesen und zu bearbeiten. Vieles was Euch in Foren und anderen Tutorials begegnet entstammt einer Zeit, als die CPU noch mit 8 oder 16 Bit gearbeitet hat und der Speicher sehr begrenzt war. Im Sinne eines gut lesbaren Code, können wir heute ruhig mal das eine oder andere Byte „verschwenden“.


Zustände
Oftmals wollen wir nur wissen ob etwas wahr oder falsch ist. Wollen wir das Ergebnis einer solchen Bedingung später nochmals verwenden, können wir das als boolean Variable festhalten. Intern wird eine „1“ oder eine „-1“ gespeichert. Wobei alles was nicht „-1“ ist als true interpretiert wird. Eine „-1“ demnach als false gilt.

  • bool Standard- Deklaration
  • Boolean die nicht Standard- Deklaration
    Leider nutzen einige Compiler verschiedener Boards diese Schreibweise. Solltes das der Fall sein, bemerkst Du dieses daran, dass das Text- Highlithing im Arduino- Fenster nicht reagiert. Sollten beide Varianten erkannt werden, nutze voranging „bool“!

Zeichen und Zeichenketten
Wir sind in unserem Beispiel schon einer solchen Zeichenkette begegnet. Als wir zum Beispiel unsere serielle Schnittstelle angewiesen haben, den Zustand des IO- Pin („D4 HIGH“) zu schreiben. Auch solche Zeichenketten können in einer Variablen gespeichert werden. Dazu gibt es in „C++“ verschiedene Möglichkeiten.

  • char speichert ein einziges Zeichen.
    Zeichen werden als Zahlen zwischen 0 und 127 gepeichert. Generell kommt hier der ASCII Code zur Anwendung.  ASCII- Tabelle auf Wikipedia
  • char[x] speichert eine Zeichenkette mit x Zeichen.
  • String speichert eine Zeichenkette undefinierter Länge.

Persönliche Anmerkung
Es ist erstaunlich, wie viele Dogmen in diesem Bereich bestehen. Wundere Dich bitte nicht, wenn Du außerhalb dieses Portals oftmals auf Kritik stößt, sobald es um den Variablentyp „String“ und die Nutzung der dazugehörigen Möglichkeiten geht. Gerade die Arduino Community muss sich hier erst daran gewöhnen, dass die Nutzung des String- Objekts keine Probleme mehr macht.
Ja es ist richtig, der Compiler erzeugt sobald man dieses nutzt ca. 120 kB an Programmcode, der im MC mit gespeichert werden muss. Wer gerade mal mit 512 kB auskommen muss, ist da natürlich empfindlich.
Wir werden uns jedoch vom Anfang an damit beschäftigen den Nutzern unserer Programme im Klartext Informationen über den Programmablauf zu bieten. Sei es über ein Handy oder über ein Display. Zudem werden wir oft auf Eingaben der Nutzer reagieren müssen. Textverarbeitung gehört also zu unserem Programmieralltag. Und im Sinne eines gut lesbaren Code, können wir dann darauf verzichten, mittels char- Zeichenketten Dinge mühsam per Hand zu programmieren. Denn einmal benutzt, benötigt das String Objekt kaum mehr zusätzlichen Speicher, wenn wir darauf nochmals zurück greifen.


Andere Variablentypen
Bei der Verwendung diverser Bibliotheken können auch noch andere Variablentypen vorkommen. Diese stehen jedoch dann im Zusammenhang mit der verwendeten Bibliothek. Wir werden uns diese dann bei Bedarf ansehen.


Namensgebung
Die Vergabe von Variablennamen obliegt Dir. (Vergib nach Möglichkeit immer einen Namen der den Wert klar bezeichnet! Einige Regeln sind jedoch genau ein zu halten.

  • Variablennamen dürfen keine reservierten Wörter sein.
    Du darfst also keine Befehle oder Funktionsnamen verwenden.
  • Groß und Kleinschreibung werden berücksichtigt.
  • Eindeutig innerhalb ihres Gültigkeitsbereichs
  • Sie beginnen immer mit einem Buchstaben.
  • Sie dürften keine Leerzeichen enthalten.
    Nutze, wenn Du eine optische Trennung wünscht das „_“ (Underline) Zeichen!

Definition einer Variablen
In C und C++ ist es zwingend erforderlich eine Variable zu definieren. Die Anweisung besteht aus dem Datentyp einem Leerzeichen und den zu vergebenden Variablennamen.

 Zuweisung
Wir können mittels des Zuweisungsoperator „=“ (das Gleichheitszeichen) der Variablen auch gleich einen Inhalt zuweisen. Grundsätzlich wird mit dem Zuweisungsoperator der Variablen vor diesem, das Ergebnis der Anweisung hinter diesem zugewiesen. Operatoren sind Zeichen oder Zeichenfolgen, die je nach dem Kontext in dem diese benutzt werden, gewisse Aufgaben erfüllen. Die vier Grundrechnungsarten werden zum Beispiel mittels der mathematischen Operatoren „+“ , „-„ , „*“ , „/“ dargestellt.
Mehr dazu in einem eigenen Beitrag.

Beachte, dass bei Zuweisung einer Zeichenkette wiederum, wie in unserem ersten Beispiel, die Zeichenkette selbst in Anführungszeichen steht. Diese Schreibweise gilt für alle Zeichenketten. Ungeachtet ob diese als „String“ oder als „char[x]“ definiert sind. Für einzelne Zeichen verwenden wir das  Hochkomma, welches wir bei der „#“ (Raute)- Taste auf unserer Tastatur finden.


Globale und lokale Variable
Als letztes sollte man sich überlegen, ob die Variable nur eine begrenzte Gültigkeit haben soll, oder im gesamten Programm Verwendung finden soll. Das mag jetzt etwas verwirrend sein, doch es ist nicht nötig für jede Variable, dauerhaft Speicher im MC zu reservieren. Zudem kann ein Variablennamen, wenn dieser jeweils nur lokal deklariert wird, mehrfach verwendet werden.

Global
Diese Variable werden außerhalb jeder Funktion am Anfang eines Sketch deklariert. Der Compiler reserviert für diese dauerhaft Speicher. Die Variable kann an jeder Stelle des Sketch verwendet werden.

Lokal
Die Deklaration erfolgt vor der ersten Verwendung, i0nnerhalb ihres Gültigkeitsbereichs und gegenüber globalen Variablen muss die Namensgebung eindeutig sein. Der Speicher der Variable wird, mit der Beendigung des Gültigkeitsbereichs frei gegeben.


Schöner Code durch freiwillige Standards
Es hat sich in „C++“ eingebürgert, dass man globale Variable mit einem Großbuchstaben beginnt und lokale Variable mit einem Kleinbuchstaben. Weiters ist es üblich Variable so zu benennen, das man ihre Zugehörigkeit erkennen kann. Dabei werden die jeweiligen Begriffe wiederum Groß geschrieben.

Dein Compiler wird keinen Fehler melden, wenn Du dich nicht daran hältst. Du wirst jedoch nach einer gewissen Zeit selbst zu schätzen lernen, wenn man sich daran hält. Verwechslungen werden so ausgeschlossen. Zudem dient es der besseren Lesbarkeit deines Codes.


Übung
Versuche das folgende Sketch gedanklich zu verstehen und voraus zu zu sagen, was im seriellen Monitor ausgegeben wird, bevor der Loop neu startet. Zur Kontrolle, ob Deine Voraussage stimmt, kannst Du dann dieses Sketch hochladen und das Ergebnis überprüfen.


Fazit:
Solltest Du jetzt noch Fragen haben, ist das völlig in Ordnung und normal. Gerade am Anfang des Prozesses, eine Programmiersprache, oder das Programmieren selbst zu erlernen, versteht man nicht den Sinn hinter gewissen Dingen. Wichtig ist, dass Du dich mit dem gelernten auseinander setzt. Eine gute Methode das gelernte zu festigen ist, Dich mit gleichgesinnten zu unterhalten und aus zu tauschen. Nutze dazu die Google Community!
Da noch einiges an elementaren Dingen fehlt, sind die Möglichkeiten für eigene Versuche kaum ausreichend um etwas interessantes zu versuchen. Doch diesen Punkt werden wir beim nächsten Beispiel überwinden.