Variable

Aus C64-Wiki

(Weitergeleitet von Variablen)
Wechseln zu: Navigation, Suche

Eine Variable ist - genauso wie in der Mathematik - ein Platzhalter in Programmen für beliebige Zahlen und Zeichen. Beim Umgang mit ihr in der Programmierung gibt es allerdings einiges zu beachten, worauf dieser Artikel detailliert eingeht.

Inhaltsverzeichnis

[Bearbeiten] Einleitung

Programme dienen in der Regel dazu, Daten einzulesen, zu verarbeiten und wieder auszugeben. Dies sind entweder konstante Werte (z.B. aus DATA-Zeilen oder per INPUT# bzw. GET# eingelesene Werte aus Dateien) oder veränderliche Werte, z.B. durch Berechnung erzeugte oder durch Eingabe (INPUT, GET) im Eingabemodus des Programms erhaltene. Damit Programme mit diesen Daten arbeiten können, werden sie mittels Variablen temporär im Speicher des Rechners abgelegt. Eine Variable dient in diesem Sinn als Platzhalter für die gespeicherten Werte. Das Programm kann jederzeit über den Variablennamen auf die nunmehr vorgehaltenen Daten zugreifen. Dabei muss der Programmierer berücksichtigen, für welche Art von Daten er welche Variablentypen benutzt (siehe unten).

Beispiel: Werden häufig wiederkehrende Zahlenwerte, z.B. 53280 (die Speicheradresse für die Bildschirmrahmenfarbe) in einer Variablen "A" gespeichert, so kann dieser Zahlenwert im weiteren Programm mit "A" jederzeit benutzt werden. Dies hat für den Programmierer den Vorteil, dass es weniger Tipparbeit gibt (und damit auch weniger Tippfehler) und außerdem spart die Verwendung von Variablen mit kurzem Namen wertvollen BASIC-Speicherplatz für das Programm ein.

[Bearbeiten] Variablen in BASIC V2

Folgende Grundvoraussetzungen gelten beim BASIC der Version 2, wie es beim C64 verwendet wird.

[Bearbeiten] Variablennamen

  • Variablennamen können gerne "sprechend" gewählt werden, also so, dass der Name auf die Verwendung der Variablen hindeutet, z.B. SCREEN = 53281 für die Adresse der Bildschirmhintergrundfarbe. Beachten muss man allerdings, dass die Benutzung von BASIC-Schlüsselwörtern (Auflistung siehe hier) als Variablennamen oder als Bestandteil davon nicht erlaubt ist. So führen z.B. Variablennamen wie SINUS oder ERSTANWAHL zur BASIC-Fehlermeldung ?SYNTAX ERROR, da sie die BASIC-Schlüsselwörter SIN bzw. TAN enthalten. Die Variablennamen ST (STATUS), TI (TIME) und TI$ (TIME$) benutzt der Interpreter bereits als Systemvariablen, was zu Überraschungen führen kann, wenn diese von einem Programmierer als "normale" Variablen verwendet werden sollen. Weiterhin darf auch FN als Variablenname nicht benutzt werden, da dies das Schlüsselwort für die Funktion FN ist.
  • Variablennamen können theoretisch eine beliebige Länge haben. Eine Namenslängenbegrenzung tritt aber natürlich durch die logische BASIC-Zeilenlänge von 80 Zeichen in Kraft. Ebenfalls beachten: Von allen Zeichen des Variablennamens werden nur die ersten beiden Zeichen vom BASIC-Interpreter beachtet. Das heißt, die beiden Variablen A$ und AA$ sind für den Interpreter unterschiedlich und können auch unterschiedlichen Text enthalten. Bei der parallelen Nutzung von AB$ und ABC$ hingegen überschreibt eine Wertzuweisung zur zweitverwendeten Variablen den Wert der zuerst verwendeten.

Zusätzlich zu den zwei Namenszeichen wird noch die Typinformation zur Unterscheidung zwischen Variablen herangezogen. Somit sind die Variablen 'AB', 'AB%' und 'AB$' nebeneinanderher konfliktfrei verwendbar.

Zur Fehlervermeidung und einfacheren Fehlersuche (Debugging) ist es sinnvoll, nur höchstens zweibuchstabige Variablennamen zu verwenden.

Beispiel für einen Konflikt bei Variablennamen:

10 A$="1"
20 AA$="2"
30 AAA$="3"
40 PRINT A$, AA$, AAA$

Bildschirmausgabe:
1     3     3

Die mangelnde Unterscheidbarkeit von langen Variablennamen gilt auch für Systemvariablen. Beispielsweise sprechen die Varianten TIME, TICKER oder TIMES allesamt die gleiche Systemvariable 'TI' an. Der Gebrauch der Namen STATUS, TIME und TIME$ sind jedoch die übliche Konvention, die man eines einheitlichen Programmbildes wegen beibehalten sollte.

  • Variablennamen dürfen aus den Buchstaben A-Z und den Zeichen 0-9 bestehen, wobei das erste Zeichen des Variablennamens ein Buchstabe sein muss. Zusätzlich dürfen zur Kennzeichnung des Variablentyps noch die Sonderzeichen "%" (für ganzzahlige Variablen) und "$" (für Zeichenkettenvariablen) genutzt werden.
  • BASIC V2 unterstützt drei verschiedene Variablentypen:
    • Gleitpunkt- oder Fließkommavariablen (Real-Variablen), 'keine Kennzeichnung', Beispiel A=1.234
    • Ganzzahlige Variablen (Integer-Variablen), Kennzeichnung durch %, Beispiel AB%=1000
    • Zeichenkettenvariablen (String-Variablen), Kennzeichnung durch $, Beispiel BA$="TEXT"

[Bearbeiten] Zuweisung bzw. Ein-/Ausgabe

Die Wertzuweisung an eine Variable kann durch verschiedene Methoden erfolgen:

  • Vorschriftsmäßig mit dem Befehl LET, z.B. so: LET A = 123.
  • Kürzer ohne den Zuweisungsbefehl LET, also so: A = 123. Beide Schreibweisen sind syntaktisch gleichwertig.
  • Auslesen von Werten aus DATA-Zeilen, die im Programmkörper selbst eingebettet sind, mit dem BASIC-Befehl READ.
  • Auslesen von Werten aus Dateien auf Band oder Disk mit den Befehlen GET# oder INPUT#.
  • Auslesen von Werten aus Speicherzellen mit PEEK.
  • Eingabe von Werten über die Tastatur während des Programmlaufs mit INPUT oder GET.

Die Ausgabe einer Variablen erfolgt ebenfalls durch verschiedene Methoden:

  • Die einfachste ist das Anzeigen des Variableninhalts auf dem Bildschirm mit dem BASIC-Befehl PRINT.
  • Per Zuweisung an eine andere Variable, evtl. bei gleichzeitiger Verarbeitung, z.B. B = A + 1.
  • Das Ausdrucken der Werte auf Papier mit dem BASIC-Befehl PRINT#.
  • Das Schreiben der Variablenwerte in eine Datei, ebenfalls mit PRINT#. Die Werte liegen in der Datei im Klartext vor (so wie ausgedruckt).

Erfolgen weitere Zuweisungen an die gleiche Variable in (logisch) nachfolgenden Programmzeilen, so wird der bisherige Variableninhalt durch den neuen überschrieben.

Wenn eine Variable ohne ausdrückliche Wertzuweisung erstmalig verwendet wird, legt der BASIC-Interpreter automatisch die entsprechende Speicherstelle für die Variable an. Bei Zahlenvariablen weist er ihr dann den Wert 0 zu. Eine Zeichenkettenvariable erhält eine leere Zeichenkette (Leerstring) als Wert. Die Variablen werden in der Reihenfolge ihrer ersten Verwendung im Speicher abgelegt. Bei der Verarbeitung und Ausgabe durchsucht der Interpreter dann diesen Speicherbereich von vorne nach hinten nach der jeweiligen Variablen. Hinten liegende werden dementsprechend zuletzt gefunden. Häufig verwendete Variablen sollten daher als (logisch) erste im Programm definiert werden (siehe auch weiter unten), um das Laufzeitverhalten des Programms zu verbessern.

[Bearbeiten] Fließkomma-/Integerzahlen

Der Unterschied zwischen einer Zahl im Fließkommaformat (auch: Gleitpunkt- oder Realzahl) und einer Integerzahl (auch: Ganzzahl) ist, dass eine Fließkommazahl Nachkommastellen besitzen kann und einen größeren Wertebereich hat. Einzelheiten dazu finden sich bei den Stichworten Integer und Fließkomma. Variablen vom Typ "Fließkomma" weisen keine besondere Kennzeichnung im Namen auf (wie z.B. "A" oder "BACKGROUND" usw.)

Bei der Ausgabe (auf den Bildschirm oder in eine Datei) werden bei Fließkommazahlen höchstens 10 signifikante Zeichen dargestellt, einschließlich dem Vorkommaanteil der Zahl und dem Dezimalpunkt. Weist die zugrunde liegende Zahl mehr Stellen auf, schaltet der Rechner um in die Exponentialschreibweise (verdeutlicht durch das Zeichen "e" für "Exponent" in der Bedeutung "mal 10 hoch").

Bei Ganzzahlen werden eventuelle Nachkommaanteile ohne weitere Behandlung einfach abgeschnitten, genau wie bei der BASIC-Funktion INT (keine echte Rundung). Das Namenskennzeichen von Integerzahlen ist das Prozentzeichen (z.B. "A%" oder "BACKGROUND%").

Beispiel für die Darstellungsweise von Integer- und Fließkommazahlen:

10 I=123.123456089: PRINT I
20 E%=I: PRINT E%
30 I=0.0000000000000123: PRINT I
40 I=12345678901: PRINT I

Bildschirmausgabe:
123.123456
123
1.23e-14
1.23456789e+10

[Bearbeiten] Zeichenketten/Strings

Variablen für Zeichenketten dürfen Zeichen des gesamten Zeichensatzes des C64 enthalten. Die Länge eines solchen Strings darf zwischen 0 (Leerstring, Zeichenkette ohne Inhalt) und 255 variieren. Das Typkennzeichen von Strings im Namen ist "$", wie z.B. bei "A$" oder "BACKGROUND$".

Die nicht von der Tastatur aus produzierbaren Zeichen, z.B. die Steuerzeichen (mit einem ASCII-Code zwischen 0 und 32 sowie 128 und 160) können über die BASIC-Funktion CHR$ in Zeichenketten eingebaut werden.

Beispiele: Soll das Anführungszeichen ("), das ja im Programmtext Strings umschließt und kenntlich macht, innerhalb eines Strings vorkommen, muss es als Code CHR$(34) mit dem Rest der Zeichenkette verbunden werden. Auch das Steuerzeichen für die Taste <RETURN> (Code 13) kann über CHR$(..) in Strings genutzt werden.

10 A$ = "Hier das Anfuehrungszeichen: " + CHR$(34)
20 B$ = "Und hier eine Zeile tiefer durch das RETURN-Steuerzeichen"+ CHR$(13)
30 PRINT "1. Teil: "; A$
40 PRINT "2. Teil: "; B$; A$

Bildschirmausgabe:
1. Teil: Hier das Anfuehrungszeichen: "
2. Teil: Und hier eine Zeile tiefer durc
h das RETURN-Steuerzeichen
Hier das Anfuehrungszeichen: "

[Bearbeiten] Felder/Arrays

Bei großen variablen Datenmengen bietet das C64-BASIC die Möglichkeit, viele zusammengehörige Werte unter einem einzigen Namen zu verwalten, das sind die Datenfelder oder Arrays. Arrays gibt es für die drei schon genannten Variablentypen (Fließkomma, Integer und String). Sie können ein- oder mehrdimensional sein. Ein eindimensionales Datenfeld muss man sich vorstellen wie eine Liste, die Daten stehen "untereinander" und sind durch die Nummer der Zeile auf dieser Liste einzeln ansprechbar (z.B. könnte in der Liste EINKAUF$(10) an Position 5 der Wert "Grillkohle" eingetragen sein, er wäre abrufbar per PRINT EINKAUF$(5) usf.) Zweidimensionale Felder sind vergleichbar mit dem Plan für ein Spielfeld, etwa für Schach: im Array BRETT%(8,8) könnten in den einzelnen Zellen die Positionen der Spielfiguren abgelegt sein. Hätte der König die Kennzahl 1, könnte er z.B. irgendwann an Position BRETT%(5,3) = 1 gesetzt werden. Entsprechendes gälte für ein Schiffe-versenken-Spiel (je Spieler ein Feld). Zweidimensionale Felder können aber auch sehr gut Tabellen abbilden (z.B. könnte BUNDESLIGA%(18,2) für jeden der 18 Vereine die Tore und Punkte enthalten, dazu käme eine Liste BUNDESLIGA$(18), die die Namen der Vereine enthielte; Ausgabe: PRINT BUNDESLIGA$(1), BUNDESLIGA%(1,1), BUNDESLIGA%(1,2)).

Theoretisch sind maximal 255 Dimensionen möglich, was allerdings an Speicherplatzgrenzen stoßen dürfte, denn der Platzbedarf wächst mit jeder Dimension stark an. Man deklariert ein Array mit dem BASIC-Befehl DIM, also z.B. so: DIM BUNDESLIGA%(18,2). Zu beachten ist, dass die Positionszählung intern für jede Dimension mit 0 beginnt, sodass im genannten Bundesliga-Beispiel 19 * 3 = 57 Tabellenzellen im Speicher reserviert werden, in diesem Fall für Integerzahlen, also mit zwei Bytes Platzbedarf pro Zelle, was einen Speicherbedarf von 114 Bytes (plus einige Verwaltungsbytes) ergäbe. Ein Fließkomma-Array gleicher Dimensionierung würde schon 285 Bytes verbrauchen. Ein Stringarray enthält bei der Anlage (vor Wertezuweisungen) außer den Verwaltungsbytes gar nichts, verschlingt daher auch keinen Platz.

Wird die Dimensionierung mit DIM unterlassen, legt der Interpreter beim ersten Aufruf einer beliebigen Zelle eines Arrays das ganze Array mit einer Größe von 11 Zellen pro Dimension an - also etwa A(10,10,10) beim erstmaligen Zugriff auf die Zelle A(1,5,0) - und belegt entsprechend viel Speicher (hier: 6655 Bytes plus 9 Verwaltungsbytes). Arrays von einem Zahlentyp werden mit dem Wert 0 pro Zelle initialisiert, Stringarrays mit Leerstrings.

Zu den Fehlermeldungen und sonstigen Details siehe beim BASIC-Befehl DIM.

[Bearbeiten] Operatoren

Operatoren dienen dazu, Daten gleicher Art nach einer festgelegten Regel miteinander zu verknüpfen. Entsprechend den drei Datentypen gibt es drei verschiedene Arten von Operatoren: numerische, logische und Zeichenketten-Operatoren. Sie werden dargestellt als bestimmte Zeichen oder Schlüsselworte: +, -, *, /, ↑, <, >, =, AND, OR und NOT. Dabei dienen Klammern dazu, die vorgegebene Ranghierarchie zu verändern. Der Inhalt des innersten Klammerpaares eines Ausdrucks wird zuerst abgearbeitet. Die höchste Verschachtelungstiefe beträgt hierbei 10 geöffnete Klammern, ansonsten erfolgt die BASIC-Fehlermeldung ?OUT OF MEMORY.

Die Rangstufung der Operatoren ist beim C64 folgendermaßen festgelegt (höchste Priorität zuoberst, dann absteigend wie angezeigt):

1Potenzierung
2+
-
Vorzeichen
3*
/
Multiplikation
Division
4+
-
Addition und Stringverkettung
Subtraktion
5<
<=
=
>=
>
<>
Vergleich
6NOTVerneinung
7ANDSowohl-als-auch-Verknüpfung
8OROder-Verknüpfung

Die logischen Operatoren AND, OR und NOT können auch zur bitweisen Verknüpfung von Zahlen herangezogen werden (beschränkt auf 16 Bit entsprechend des zulässigen Integer-Wertebereichs).

Beispiele: 

Mathematische Operationen:
 Addition: C=A+B
 Subtraktion: C=A-B
 Multiplikation: C=A*B
 Division: C=A/B 
  Eine Division durch 0 wird nicht zugelassen 
  und die BASIC-Fehlermeldung 
  ?DIVISION BY ZERO ausgegeben.
 Negatives Vorzeichen: C=-B 
  oder C=2-(-4)
 Potenzen: C=2↑2
 Verwendung von Exponenten: C=A+1E+6
 Verwendung von PI ("π"; Konstante mit dem Wert 3,141592654):
  C=D*π 

Vergleichoperatoren erlauben die Werte von Variablen und 
Funktionen zu verknüpfen, um üblicherweise in einer 
IF-THEN- oder ON-GOTO/GOSUB-Konstruktion 
den Programmlauf zu steuern: 
 IF A < B THEN 200

Logische Operationen AND, OR und NOT bilden 
eigenständige oder mit Vergleichsoperatoren komplexere
Ausdrücke für die Steuerung des Programmlaufs
(Entscheidungen nach Wahrheitsgehalt):
 10 ON (X AND Y)+2 GOTO 100, 200
 99 REM X, Y: 0 | -1 ... FALSCH | WAHR
 100 PRINT "WAHR":END
 200 PRINT "FALSCH":END

Logische Bitverknüpfungen mit AND, OR und NOT: 
 REM BIT 6 EINER SPEICHERSTELLE SETZEN:
 POKE 53269, PEEK(53269) OR 64

Stringverkettung: C$ = A$ + B$

[Bearbeiten] Funktionen

Variablen können durch folgende mathematische Funktionen verarbeitet werden: ABS, ATN, COS, EXP, FN, INT, LOG, RND, SGN, SIN, SQR, TAN. Darüber hinaus stehen die Systemfunktionen FRE, POS und USR, sowie die Systemvariablen STATUS (ST), TIME (TI) und TIME$ (TI$) zur Verfügung. Zur Bearbeitung von Zeichenkettenvariablen, u.a. Teile von Zeichenketten zuschneiden, gibt es LEFT$, MID$, RIGHT$.

Um Variablentypen ineinander umzuwandeln, stellt der Interpreter die Funktionen ASC, VAL (Zeichen oder Zeichenkette in Zahl), CHR$, STR$ (Zahl in Zeichen oder Zeichenkette) bereit und schließlich dient LEN dazu, die Länge einer Zeichenkette als Zahl zu ermitteln.

[Bearbeiten] Platzverbrauch

Der Platzverbrauch beträgt für Variablen unabhängig vom Typ 7 Bytes: 2 Bytes für den Variablennamen und die Typcodierung, sowie 5 weitere Bytes, die unterschiedlich genutzt werden:

  • Gleitpunkt- oder Fließkommavariablen: 1 Byte Exponent plus 4 Bytes Mantisse,
  • Ganzzahlige Variablen: 2 Bytes für einen 16-Bit-Integer-Wert (Rest enthält 0),
  • Zeichenkettenvariablen: 3 Bytes für den Stringdescriptor (1 Byte Längenangabe und 2 Bytes als Zeiger auf den eigentlichen Zeichenketteninhalt, Rest enthält 0)

Variablen in einem Feld/Array werden platzsparender verwaltet. Neben den Verwaltungsdaten fallen pro Zelle nur noch die Daten für den jeweiligen Variablentypen (siehe oben) je Feldelement an. D.h. eine Integerzelle verbraucht in einem Array zwei, eine Stringzelle drei und eine Fließkommazelle fünf Bytes.

[Bearbeiten] Interne Organisation der Variablen

  • Variablen werden im BASIC-Speicher anschließend an das BASIC-Programm verwaltet (bis maximal MEMSIZ). Das Editieren des Programms löscht alle Variablen (implizites CLR).
  • Variablenzugriff und dessen Laufzeitverhalten:
    • Die Erstverwendung einer Variable bestimmt auch die Reihenfolge der Variablen im jeweiligen Variablenspeicherbereich. Da der BASIC-Interpreter Variablen stets sequentiell vom Variablenbereichsanfang her durchsucht, wird eine früher definierte oder verwendete Variable schneller gefunden. Häufig genutzte Variablen (z.B. Indizes/Zähler) sollten daher explizit möglichst früh im Programmablauf definiert werden, um Laufzeit zu sparen.
    • Die erste Zuweisung einer bisher nicht angelegten, einfachen Variablen kann im Vergleich zu weiteren Zuweisungen deutlich länger dauern, wenn bereits sehr umfangreiche bzw. große Arrays existieren. Denn der Bereich für indizierte Variablen muss nämlich für jede neu angelegte einfache Variable im Speicher vollständig verschoben werden, um Platz im Bereich für einfache Variablen zu schaffen. Das kann z.B. bei einem String-Array von 9000 Elementen bereits 0,5s in Anspruch nehmen (die Zuweisung dauert dann mehr als 30 mal länger).
  • Steht kein freies Basic-RAM mehr zur Verfügung, führt der Interpreter eine Garbage Collection durch, die den Speicherplatz nicht mehr referenzierter Strings freigibt, der dann von neuen Variablen, aber auch erneut von Stringwerten verwendet werden kann.

[Bearbeiten] Weblinks

WP-W11.png Wikipedia: Mantisse
WP-W11.png Wikipedia: Variable


Programmiersprachen-Portalseite
C64-BASIC: BASIC V2 · BASIC-Befehle · Variable

C64-Assembler: Assembler · Assembler-Befehle · KERNAL-ROM · BASIC-ROM · Speicherbelegungsplan
Persönliche Werkzeuge
In anderen Sprachen