Schnelltipp: Bildschirm unter BlitzBasic löschen

Beim Schreiben von Programmen für die Shell steht man manchmal vor dem Problem, den Bildschirm (eigentlich: Den Inhalt der Shell) löschen zu müssen. Die meisten BASIC-Dialekte verfügen zu diesem Zweck über Befehle wie CLS oder CLEARSCR. Bei BlitzBasic/AmiBlitz3 sind die aber bereits zu anderen Zwecken belegt, es existiert kein eigener Befehl für diesen Zweck.

Abhilfe schafft hier der Umweg über die Ausgabe von Escape-Codes. Dazu hat man zwei Möglichkeiten:

Kompatible Variante

Print Chr$($0c)

Diese Variante läuft unter allen BlitzBasic-Versionen einschließlich AmiBlitz3. Sie druckt das ESC-Zeichen zum Löschen des Bildschirms. Wenn der Befehl öfter im Programm gebraucht wird, dann kann man ihn auch in einer „sprechenden“ String-Variable ablegen:

scrclr.s = Chr$($0c)

Der Aufruf erfolgt dann einfach über die Anweisung: Print scrclr.

Diese Lösung funktioniert sogar unter PureBasic 4.0 Amiga:

; ----------------------------------
; File: scrclr.pb
; Bildschirm löschen
; Version für PureBasic v4.0 (Amiga)
; Revision: v1.0.1
; ----------------------------------


; -- Variablen definieren --
scrclr.s = chr($0c)

Print(scrclr)
PrintN( "***********************************")
PrintN( "* Bildschirm loeschen - Variante 1 *")
PrintN( "*************************************")
PrintN("")
PrintN( "Ich loesche nun den Bildschirm...")
PrintN( "Weiter: Linke Maustaste ")
MouseWait()
Print(scrclr)

PrintN( "E N D E ")
PrintN("")

 

Das folgende Listing zeigt die BlitzBasic-Variante:

; -----------------------------------
; File: scrclr1.ab3
; Bildschirm loeschen per ESC-Sequenz
; Version: 1.0 (BlitzBasic/AmiBlitz3)
; -----------------------------------

; Amiga Version String und das Compilerdatum
!version {"ScrClr 1.0 (\\__DATE_GER__)"}

; -- Globale Variablen deklarieren --
bScrClr.s = Chr$($0c)            ; bb2-Variante

; -- ScrClr: bb2-Variante --
NPrint "***********************************"
NPrint "* Bildschirm loeschen - Variante 1 *"
NPrint "*************************************"
NPrint"":NPrint "Ich loesche nun den Bildschirm..."
Print "Weiter: Linke Maustaste "
MouseWait
Print bScrClr
NPrint "E N D E "

End

 

AmiBlitz3-Variante

Selbstverständlich funktioniert die zuvor beschriebene Methode auch unter AmiBlitz3 – allerdings hält der neue Compiler auch eine eigene Möglichkeit vor: Hier muss man aber etwas mehr an Vorbereitung investieren. Zunächst muss AmiBlitz3 für seinen erweiterten Syntax konfiguriert werden: OPTIMIZE 4
Danach gibt man zwei ESC-Sequenzen in Fluchtzeichendarstellung aus:
Print „\\1B[1m“ : Print „\\1Bc“ 

Das folgende Listing zeigt die AmiBlitz3-Variante:

; -----------------------------------
; File: scrclr2.ab3
; Bildschirm loeschen per ESC-Sequenz
; Version: 1.0 (AmiBlitz3-only)
; -----------------------------------
OPTIMIZE 4  ; aktiviere den neuen Syntax von AmiBlitz3
SYNTAX 2

; Amiga Version String und das Compilerdatum
!version {"ScrClr 1.0 (\\__DATE_GER__)"}

; -- Globale Variablen deklarieren --
aScrClr.s = "\\1B[1m" + "\\1Bc"  ; ab3-Variante

; -- ScrClr: ab3-Variante --
NPrint "***********************************"
NPrint "* Bildschirm loeschen - Variante 2 *"
NPrint "*************************************"
NPrint"":NPrint "Ich loesche nun den Bildschirm..."
Print "Weiter: Linke Maustaste "
MouseWait
Print aScrClr
NPrint "E N D E "

End

Diese Variante ist nicht abwärtskompatibel zu BlitzBasic!


[Übersicht]

BlitzBasic mit AmiBlitz3 - ein Tutorial für Amiga-Programmierer www.mbergmann-sh.de

BlitzBasic für Einsteiger – Variablen, Konstanten und Datentypen

Wer in den frühen Jahren der IT z.B. auf dem Commodore 64 in BASIC programmiert hat, der brauchte sich keine Gedanken um die Interna von Variablen und Konstanten zu machen. Es gab Variablen für Strings und Zahlen – und damit basta. Das hat sich mit modernen BASIC-Dialekten aus guten Gründen drastisch geändert.

Variablen belegen per se ein Stück zusammenhängenden Arbeitsspeicher (RAM) pro Stück. Aus heutiger Sicht ist es deshalb nicht effizient, für jede Variable eine gleich große Menge Arbeitsspeicher zu vergeuden. Manchmal möchte man nur mit sehr kleinen Zahlen arbeiten, ein andermal  mit Fließkommazahlen und wieder ein anderes Mal benötigt man Platz für sehr große Zeichenketten (Strings). Das ist der Punkt, an dem Datentypen ins Spiel kommen.

Wenn man für eine Variable immer nur so viel Speicher reserviert, wie tatsächlich gebraucht wird, dann verschwendet man weniger knappe Ressourcen (RAM) – aber es ergibt sich daraus noch ein weiterer Vorteil: Kleine Ganzzahlen werden vom Computer schneller verarbeitet, als z.B. große Fließkommazahlen.

Es ist auch unter BlitzBasic/AmiBlitz3 möglich, beim Schreiben von Programmen völlig darauf zu verzichten, sich mit Datentypen auseinanderzusetzen. Der Compiler geht dann intern einfach davon aus, dass er den Default-Datentyp verwenden soll. Unter AmiBlitz3 ist das QUICK (vergl. Anhang A – primitive Datentypen). Dieser Datentyp verbraucht entsprechend viel Ressourcen, da er ja groß genug für alle anfallenden Arten von Zahlen sein muss. Effizienter ist es da natürlich, sich die benötigte Größe der verwendeten Variablen vorher zu überlegen und sie mit einem passenden Datentyp zu deklarieren.

Variablen und ihr Datentyp

Eine Variable ist ein abstrakter Behälter für einen Wert, der bei der Ausführung eines Computerprogramms auftritt. Im Normalfall wird eine Variable im Quelltext durch einen Namen bezeichnet und hat eine Adresse im Speicher des Computers. Der durch eine Variable repräsentierte Wert (und gegebenenfalls auch die Größe) kann – im Unterschied zu einer Konstante – zur Laufzeit des Programms verändert werden. Variablen dienen also dazu, veränderbare Werte zu speichern.

Unter BlitzBasic/AmiBlitz3 definiert man eine Variable mittels des Schlüsselworts DEFTYPE nach dem folgenden Schema:

DEFTYPE .Datentyp Variablenname
; -- Beispiel, deklariert eine Variable vom Typ String: --
DEFTYPE .s altesKinderlied
altesKinderlied = "Alle meine Entchen"

Es ist auch mögliche, eine Variable direkt, ohne DEFTYPE zu deklarieren:

altesKinderlied.s = "Alle meine Entchen"

Der Variablenname ist im Rahmen syntaktischer Vorgaben frei wählbar. Er sollte aussagekräftig den Zweck der Variablen wiedergeben („sprechender“ Name). Erlaubt sind alphanumerische Zeichen und der Unterstrich mit den folgenden Ausnahmen:

  • der Variablenname darf nicht gleichlautend mit einem Schlüsselwort sein.
  • das erste Zeichen darf keine Ziffer sein.
  • Umlaute sind nicht erlaubt.
  • Sonderzeichen außer dem Unterstrich sind nicht erlaubt.
    Ausnahmen: Sonderzeichen, die zur Identifizierung eines Datentypen gehören, dürfen am Anfang oder Ende des Variablennamens verwendet werden.

Beispiele:

; Erlaubt:
meinString$, meinString.s
meine_variable1
aepfelZaehler

; Verboten:
mein$tring
1teVariable
äpfelZähler

Der Datentyp legt den Speicherverbrauch einer Variablen fest.

Primitive Datentypen

BlitzBasic/AmiBlitz3 verfügt über 7 Basis-Datentypen – die sogenannten primitiven Datentypen. Die Sprache verfügt auch über die Möglichkeit, aus diesen Typen erweiterte, die sogenannten zusammengesetzten Datentypen, zu erstellen – doch dazu später mehr.

Jedem primitiven Datentyp ist ein bestimmter Wertebereich zu eigen, in dessen Rahmen er Zahlen und Zeichen darstellen kann. Die Größe dieses Wertebereich bestimmt seinen Speicherverbrauch (vergl. Anhang A – primitive Datentypen).

Byte (.b)

Dieser Datentyp verarbeitet kleine Ganzzahlen (Integerwerte) im Wertebereich von -128 bis +127 (-128 … 0 … +128) und verbraucht 1 Byte (8 Bits) Speicher. Er eignet sich z.B. gut als Zählervariable in kurzen Zählschleifen oder zur numerischen Darstellung des ASCII-Zeichensatzes.
Beispiel: DEFTYPE .b kleinerZaehler =  0

Word (.w)

Dieser Datentyp verarbeitet mittelgroße Ganzzahlen im Wertebereich von -32768 bis +32767 (-32768 … 0 … +32767) und verbraucht 2 Bytes (16 Bits) Speicher.
Beispiel: DEFTYPE .w fatNumber =  22000

Long / Long Word (.l)

Dieser Datentyp verarbeitet sehr große Ganzzahlen im Wertebereich von -231  bis +231 und verbraucht 4 Bytes (32 Bits) Speicher.
Beispiel: DEFTYPE .l veryfatNumber =  4711081542

Quick (.q)

Dieser Datentyp verarbeitet kleine Fließkommazahlen im Wertebereich von -32768 bis +32767 unter Verwendung eines festen Dezimalpunkts und verbraucht 4 Bytes (32 Bits) Speicher, erlaubt bis zu 10 Nachkommastellen. Er ist schneller als die Emulation der Float-Typen in Software, aber langsamer als Integer und langsamer als Float-Typen auf einer Hardware-FPU.
Beispiel: DEFTYPE .q smallFloatNumber = 4711.0815

Float (.f)

Dieser Datentyp verarbeitet große, einfachpräzise Fließkommazahlen im Wertebereich von -9*1018 bis +9*1018-1 und verbraucht 4 Bytes (32 Bits) Speicher. Er eignet sich besonders zur Verwendung als einfachpräzise Fließkommazahl, wie sie von den Standard-Fließkommabibliotheken des Amiga unterstützt wird und arbeitet mit +/-23bits+/-7 bits (10 Nachkommastellen)Dieser Datentyp ist sehr langsam in Software zu emulieren, aber sehr schnell, wenn Hardware-FPU verwendet wird. Er arbeitet langsamer als Ganzzahlen.
Beispiel: DEFTYPE .f largeFloatNumber = 471143.0815

Double Float (.d)

Dieser Datentyp verarbeitet sehr große, doppeltpräzise Fließkommazahlen mit riesigem Wertebereich und verbraucht 8 Bytes (64 Bits) Speicher, 9 Nachkommastellen. Keine Software-Emulation möglich, daher muss eine Hardware-FPU vorhanden sein, um diesen Datentyp nutzen zu können! Nicht unterstützt in Blitz Basic 2.1 und früher. Langsamer als einfachpräzise Float-Typen. Typische Anwendungsfälle wären ein Programm zur Berechnung von Zinsen über lange Zeiträume oder eine ähnliche Banking-Software und alle Anwendungen, die wissenschaftliche Berechnungen mit Bedarf an hoher Rechengenauigkeit durchführen.
Beispiel: DEFTYPE .d hugeFloatNumber = 471143.0815

Hinweis: Der Inhalt einer Variablen des neuen Datentyps Double Float kann nicht korrekt mit Print und NPrint ausgegeben werden! Beide Befehle liefern nur den ganzzahligen Anteil des Wertes einer Variablen dieses Datentyps – die Stellen nach dem Dezimalpunkt werden von beiden Befehlen unterschlagen. Derzeit unterstützt noch keine einzige BlitzLib diesen Datentypen, sodass er hier nur der Vollständigkeit halber aufgeführt ist! Wenn es vermeidbar ist, dann verwende diesen Datentyp nicht.
Benutze stattdessen den Datentyp Float.

String (.s oder $)

Dieser Datentyp verarbeitet Zeichenketten aus 8-Bit-Zeichen im Speicher, die automatisch durch ein Nullzeichen (\0) abgeschlossen werden und verbraucht 4 Bytes (32 Bits).
Beispiel 1: DEFTYPE .s myStringVar_1
myStringVar_1 = „Ich bin eine Zeichenkette!“
Beispiel 2: myStringVar_2.s = „Ich auch! Ich auch!“
Beispiel 3: myStringVar_3$ = „Und ich erst!“

Datentypen deklarieren

Bei der Deklaration von Datentypen unterscheidet man zwischen der Inline-Deklaration, der expliziten Deklaration und der globalen Festlegung eines bestimmten Default-Datentyps:

  • Inline: ergebnis.q = 4711.42 (die Variable wird mit dem angegebenen Typen – hier: QUICK – versehen und gleichzeitig mit einem Wert initialisiert)
  • Explizit: DEFTYPE .q ergebnis (die Variable – und nur diese – ist vom angegeben Typ. Hier: QUICK)
  • Global: DEFTYPE .q (alle nicht inline oder explizit deklarierten Variablen sind vom Typ, der hier angegeben wurde – in diesem Fall QUICK)

Das Listing „typesize.ab3“ demonstriert die Deklaration und Initialisierung der primitiven Datentypen und gibt deren Speicherbedarf in Bytes und Bits aus. Beachte, dass dieses Listing aufgrund der Verwendung des Datentyps DOUBLE FLOAT nur auf Amigas mit FPU compiliert werden kann!

; ---------------------------------
; Listing: typesize.ab3
; Speicherverbrauch von Datentypen
; Version 1.0
;
; HARDWARE-FPU ERFORDERLICH!
; ---------------------------------
OPTIMIZE 3 ; FPU zuschalten
SYNTAX 1   ; strenger Syntax-Check

; -- Variablendeklaration mit DEFTYPE --
DEFTYPE .b byteVar
DEFTYPE .w wordVar
DEFTYPE .l longVar
DEFTYPE .q quickVar
DEFTYPE .f floatVar
DEFTYPE .d doubleVar
DEFTYPE .s stringVar, byteRes, bitRes

; Amiga Version string und das Compilerdatum
!version {"typesize 1.0 (\\__DATE_GER__)"}

; Variablen initialisieren
byteVar   = -128
wordVar   = 32767
longVar   = 4711081542
quickVar  = 4711.0815234567
floatVar  = 471143.0815421112
doubleVar = 47114384.420815471
stringVar = "BlitzBasic macht Freude."

; Werte ausgeben
byteRes = Str$(SizeOf .b)
bitRes  = Str$((SizeOf .b) * 8)
Print "Speicherverbrauch BYTE: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint byteVar
NPrint ""

byteRes = Str$(SizeOf .w)
bitRes  = Str$((SizeOf .w) * 8)
Print "Speicherverbrauch WORD: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint wordVar
NPrint ""

byteRes = Str$(SizeOf .l)
bitRes  = Str$((SizeOf .l) * 8)
Print "Speicherverbrauch LONG: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint longVar
NPrint ""

byteRes = Str$(SizeOf .q)
bitRes  = Str$((SizeOf .q) * 8)
Print "Speicherverbrauch QUICK: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint quickVar
NPrint ""

byteRes = Str$(SizeOf .f)
bitRes  = Str$((SizeOf .f) * 8)
Print "Speicherverbrauch FLOAT: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint floatVar
NPrint ""

byteRes = Str$(SizeOf .d)
bitRes  = Str$((SizeOf .d) * 8)
Print "Speicherverbrauch DOUBLE FLOAT: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint doubleVar  ; ACHTUNG: NPrint und Print drucken nur den ganzzahligen 
                  ; Anteil des Wertes!
NPrint "ACHTUNG: Ungelöstes Ausgabe-Problem!"
NPrint ""

byteRes = Str$(SizeOf .s)
bitRes  = Str$((SizeOf .s) * 8)
Print "Speicherverbrauch STRING: " + byteRes + " Byte ("
NPrint bitRes + " Bits)"
Print "Wert: "
NPrint stringVar
NPrint ""

End

Ausgabe:

Speicherverbrauch BYTE: 1 Byte (8 Bits)
Wert: -128

Speicherverbrauch WORD: 2 Byte (16 Bits)
Wert: 32767

Speicherverbrauch LONG: 4 Byte (32 Bits)
Wert: 416114246

Speicherverbrauch QUICK: 4 Byte (32 Bits)
Wert: 4711.5781

Speicherverbrauch FLOAT: 4 Byte (32 Bits)
Wert: 471143.5625

Speicherverbrauch DOUBLE FLOAT: 8 Byte (64 Bits)
Wert: 47114384
ACHTUNG: Ungelöstes Ausgabe-Problem!

Speicherverbrauch STRING: 4 Byte (32 Bits)
Wert: BlitzBasic macht Freude.

Programmanalyse:

Das Programm benutzt zwei neue Befehle: Str$() und SizeOf. Str$() wandelt einen numerischen Wert in einen String um. Sizeof liefert den Speicherverbrauch eines Datentyps in Bytes zurück.

Wir verwenden Str$, um den (numerischen) Rückgabewert von Sizeof einer String-Variable zuweisen zu können, die dann bei der Ausgabe durch Print und NPrint zusammen mit anderen Zeichenketten zu einer neuen Zeichenkette zusammengesetzt wird (String Concatenation).

Ablauf:

  • In Zeile 8 sorgen wir mit OPTIMIZE 3 dafür, dass neben der Optimierung für die MC68020 CPU auch die FPU verwendet wird (siehe Abschnitt „Optimierte Programme erzeugen“ im Artikel „Das erste Programm„). Das ist nötig, da wir u.a. den Datentyp DOUBLE FLOAT verwenden, der nur auf einer physisch vorhandenen FPU und erst ab AmiBlitz3 verwendet werden kann. BlitzBasic v2 und älter kennen diesen Datentypen nicht.
  • Zeile 9 schaltet die strenge Syntax-Prüfung ein, bei der alle Variablen vor ihrer ersten Verwendung per DEFTYPE deklariert werden müssen.
  • In den Zeilen 12 bis 18 deklarieren wir per expliziter Deklaration die im Programm verwendeten Variablen mit einem Datentyp.
  • Zeile 21 legt den Versions-String fest, der bei Abfrage mit dem DOS-Befehl version meinProgramm full in einer Shell Auskunft über die Versionsnummer und das Erstellungsdatum eines Programms gibt.
  • In den Zeilen 24 bis 30 weisen wir einigen der zuvor deklarierten Variablen Werte zu (Initialisierung).
  • Die Zeilen 33 bis 39 geben Speicherverbrauch und Inhalt der BYTE-Variablen byteVar aus:
  • In Zeile 33 wandeln wir die per SizeOf .b abgefragte Speichergröße (Anzahl Bytes) mittels Str$ in eine Zeichenkette um und weisen sie der String-Variablen byteRes zu.
  • In Zeile 34 verfahren wir analog, berechnen hier aber die Anzahl Bits durch Multiplikation mit dem Faktor 8 ( 1 Byte = 8 Bits). Das Ergebnis der Berechnung wird der String-Variablen bitRes zugewiesen.
  • In Zeile 35 geben wir per Print (ohne Zeilenvorschub) eine Teilmeldung aus. Sie setzt sich aus mehreren Teilstrings zusammen, die wir mit dem Verknüpfungsoperatur „+“ zu einem Gesamtstring für die Ausgabe zusammensetzen.
  • In Zeile 36  geben wir mit NPrint (mit Zeilenvorschub) einen weiteren zusammengesetzten String aus, der die Ausgabe der Speichergröße abschließt.
  • Zeile 37 druckt per Print eine weitere Meldung ohne Zeilenvorschub, an welche dann in Zeile 38 per NPrint der Wert (Inhalt) der Variablen byteVar angehängt und anschließend ein Zeilenvorschub ausgeführt wird.
  • Zeile 39 druckt mittels einem an NPrint übergebenen Leerstring einen weiteren Zeilenvorschub (ohne Text).
  • Analog zu den Zeilen 33 bis 39 werden in den Zeilen 41 bis 89 nacheinander die Speichergrößen und Inhalte für die übrigen Datentypen ausgegeben.
  • Das Programm endet in Zeile 91 mit der Anweisung End.

Speicherüberlauf 

Wir haben gelernt, dass jeder Datentyp einen bestimmten Wertebereich besitzt, der die Größe der darstellbaren Inhalte einer Variablen bestimmt. Was aber, wenn dieser Wertebereich überschritten wird? Nun, in diesem Fall kommt es zum Speicherüberlauf. Bei numerischen Variablen hat das zur Konsequenz, dass ihr Inhalt nicht mehr mit dem vermuteten Wert übereinstimmt, was wiederum zu unvorhergesehenem Programmverhalten führt.

Wenn ein Wertebereich überschritten wird, so wird (normalerweise) kein Fehler erzeugt. Stattdessen wird der Wert auf das andere Ende des Wertebereichs umgeschlagen. Dies kann dazu führen, dass einige sehr schwer zu findende Fehler in deinen Code eingeschleust werden!

Ein Beispiel: Der Datentyp BYTE kann Ganzzahlen im Bereich zwischen -128 und + 127 darstellen. Wenn eine BYTE-Variable den Wert +127 besitzt und man addiert nochmal 1 dazu, so ist der Inhalt nicht, wie man vermuten könnte, +128, sondern -128. Das entspricht der unteren Grenze des Wertebereichs. Addiert man nun eine weitere 1 hinzu, so ist der Wert -127.

Im negativen Wertebereich verhält sich das genauso: Wenn eine BYTE-Variable den Wert -128 besitzt und man subtrahiert davon 1 weg, so ist der Inhalt nicht, wie man vermuten könnte, –129, sondern +127. Das entspricht der oberen Grenze des Wertebereichs. Subtrahiert man nun eine weitere 1, so ist der Wert +126. Das Listing „overflow.ab3“ verdeutlicht das eben Gesagte:

; ---------------------------------
; Listing: overflow.ab3
; Ueberlauf von Datentypen
; Version 1.0
; ---------------------------------
OPTIMIZE 1 ; MC68020+ Optimierungen
SYNTAX 1   ; strenger Syntax-Check

; -- Variablendeklaration mit DEFTYPE --
DEFTYPE .b byteVar

; Amiga Version string und das Compilerdatum
!version {"overflow 1.0 (\\__DATE_GER__)"}

; Variable initialisieren
byteVar   = 127 ; positive Obergrenze

; Titel ausgeben
NPrint "=============="
NPrint "-- Overflow --"
NPrint "=============="
NPrint ""

; Wert ausgeben (positiver Bereich)
NPrint "positiver Wertebereich:"
Print "byteVar hat den Anfangswert: "
NPrint byteVar
NPrint "Addiere 1..."
byteVar = byteVar + 1
Print "byteVar hat nun den Wert "
NPrint byteVar
NPrint "Addiere weitere 1..."
byteVar = byteVar + 1
Print "byteVar hat nun den Wert "
NPrint byteVar
NPrint ""

; Wert zuruecksetzen auf Untergrenze
byteVar = -128

; Wert ausgeben (negativer Bereich)
NPrint "Negativer Wertebereich:"
Print "byteVar hat den Anfangswert "
NPrint byteVar
NPrint "Subtrahiere 1..."
byteVar = byteVar - 1
Print "byteVar hat nun den Wert "
NPrint byteVar
NPrint "Subtrahiere weitere 1..."
byteVar = byteVar - 1
Print "byteVar hat nun den Wert "
NPrint byteVar
NPrint ""

NPrint "Habe fertig."
End

Ausgabe:

==============
-- Overflow --
==============

positiver Wertebereich:
byteVar hat den Anfangswert: 127
Addiere 1...
byteVar hat nun den Wert -128
Addiere weitere 1...
byteVar hat nun den Wert -127

Negativer Wertebereich:
byteVar hat den Anfangswert -128
Subtrahiere 1...
byteVar hat nun den Wert 127
Subtrahiere weitere 1...
byteVar hat nun den Wert 126

Habe fertig.

Zum Programmablauf gibt es eigentlich nichts zu sagen – alle vorkommenden Anweisungen und Abläufe haben wir bereits besprochen.

Konstanten

Eine Konstante (von lateinisch constans ‚feststehend‘) in einem Computerprogramm ist ein Behälter für einen Wert, der nach der Zuweisung nicht verändert werden kann. Im Gegensatz zu Variablen ist der einmal festgelegte Wert einer Konstanten zur Laufzeit des Programms bindend.

Ein Rautezeichen (#) vor einem Variablennamen bedeutet, dass es sich um eine Konstante handelt (nicht mehr um eine Variable!) Der Wert einer Konstante ist immer eine Ganzzahl. Anders als in anderen Hochsprache, wie z.B. C/C++, kann man in BlitzBasic keine Konstanten mit anderen Datentypen definieren.

Konstanten haben die folgenden Eigenschaften:

  • Sie sind schneller als Variablen und benötigen keinen Speicherplatz.
  • machen Programme besser lesbar als Zahlen
  • Können in Assembler verwendet werden
  • Können mit bedingten Kompilierauswertungen verwendet werden
  • Können nur Integer-Werte enthalten
  • Erleichtert das Ändern einer konstanten Menge, die in einem Programm verwendet wird
  • Können nur über den Quellcode zur Kompilierzeit, aber NICHT zur Laufzeit geändert werden

Neben der Option, eigene Konstanten zu definieren, bringt BlitzBasic schon viele „eingebaute“ Konstante, wie bspw. die Kreiszahl Pi mit. Der wohl wichtigste Aspekt von Konstanten aus der Sicht eines BASIC-Programmierers ist aber wohl, dass alle „magischen Zahlen“, die im Code auftauchen, durch sinnvolle Worte wie #width ersetzt werden können („sprechende“ Namen!).

Das Listing „constants.ab3“ demonstriert die Verwendung von Konstanten.:

; -------------------------
; File: constants.ab3
; Zeigt die Verwendung von
; Konstanten
; Version: 1.0
; -------------------------
OPTIMIZE 1
SYNTAX 1

; Amiga Version String und das Compilerdatum
!version {"constants 1.0 (\\__DATE_GER__)"}

; Konstanten definieren:
#width  = 5
#height = 5

; Variablen deklarieren:
DEFTYPE .w area

; Flaeche berechnen:
area = Abs(#width * #height)

; Ergebnis ausgeben:
Print "Die Flaeche aus " + Str$(#width)
Print " m mal " + Str$(#height)
NPrint " m betraegt " + Str$(Abs(area)) + " qm"
; Interne Konstante Pi ausgeben:
NPrint "Der Wert der Kreiszahl PI ist " + Str$(Pi)
End

Ausgabe:

Die Flaeche aus 5 m mal 5 m betraegt 25 qm
Der Wert der Kreiszahl PI ist 3.141592

Programmanalyse:

Das Programm verwendet den neuen Befehl Abs(). Er dient zur Umwandlung vorzeichenbehafteter Zahlen in vorzeichenlose Zahlen. Wir verwenden ihn zur Umwandlung des in der Variablen area gespeicherten Wertes, der als Produkt der Multiplikation zweier Konstanten sonst u.U. als negative Zahl ausgegeben werden könnte.

  • in den Zeilen 14 und 15 definieren wir die Konstanten #width und #height. Sie werden später zur Berechnung einer Fläche herangezogen.
  • in Zeile 18 deklarieren wir die Variable area als Variable vom Typ WORD.
  • in Zeile 21 berechnen wir die Summe der Fläche und weisen das Ergebnis der Variablen area zu.
  • die Zeilen 24 bis 26 dienen der Ausgabe der berechneten Werte. Dabei benutzen wir in Zeile 26 den zuvor erklärten Befehl Abs() zur Umwandlung des in area gespeicherten Wertes – just to make sure…
  • in Zeile 28 geben wir den Wert der internen Konstante Pi aus.
  • Das Programm endet mit Zeile 29.

Zusammenfassung:

In diesem Teil des Tutorials haben wir gelernt

  • Was Datentypen und Variablen sind, welche Datentypen es gibt und wie man Variablen deklariert und initialisiert.
  • das der neue Datentyp DOUBLE FLOAT nur mit AmiBlitz3 verwendet werden kann, eine vorhanden FPU voraussetzt – und das man ihn besser nicht verwenden sollte, was sich aber in einer späteren Version von AmiBlitz3 noch ändern kann.
  • was Konstanten sind und wie man sie definiert und verwendet.
  • dass Konstanten nur Ganzzahlen aufnehmen können und keinen Speicherplatz belegen.

Ausblick

Im nächsten Teil des Tutorials werden wir uns eingehend mit den Grundrechenarten und eigenen Funktionen unter BlitzBasic beschäftigen.

 

[Zurück zur Übersicht] | [zurück] | [vowärts]

QuickBasic für Linux - QB64 unter Debian 12 installieren - www.mbergmann-sh.de

QuickBasic für Linux – QB64 unter Debian Linux Bookworm installieren

Ein Retro-Computing Abenteuer

BASIC ist ja die Sprache, mit der die Meisten meines Jahrgangs ihre ersten Schritt als Programmierer gemacht haben. Bei mir waren das Commodore BASIC 2.0 auf dem legendären C64, Commodore BASIC 3.5 auf dem C16/Plus4, AmigaBasic, GFA-Basic und MaxonBASIC auf dem Amiga – und natürlich GW-BASIC und Microsoft QuickBasic auf der ersten MS-DOS-Kiste in meiner Raupensammlung. Nach wie vor ist BASIC eine Programmiersprache, die viele Vorteile bietet: Sie ist leicht zu erlernen, je nach BASIC-Dialekt auch für mächtige Programmimplementierungen gut zu gebrauchen – und BASIC macht Spaß.

Auch heute noch verwende ich gerne mal BASIC für schnelle Entwürfe und Machbarkeitsstudien (PureBASIC), aber auch für komplexere Programme, wenn ich nicht auf C++ und Qt6 zurückgreifen möchte. Oft liefern mir dabei alte BASIC-Listings die Ideen für die Umsetzung von Programmen – und hier kommt QB64 ins Spiel…

Was ist QB64?

QB64 (ursprünglich QB32) ist ein BASIC-Compiler für Windows, Linux und Mac OS X, der für die Kompatibilität mit Microsoft QBasic und QuickBASIC entwickelt wurde. QB64 emittiert C-Quellcode und integriert selbst einen C++-Compiler, um die letztendliche Kompilierung des generierten Zwischencodes mit gcc-Optimierung zu ermöglichen. Mit der derzeit technisch genauesten Nachbildung des originalen Microsoft-Produkts zählt QB64 zu den Anwendungen im Bereich Retrocomputing.

QB64 implementiert die meisten QBasic-Funktionen und kann viele QBasic-Programme ausführen, einschließlich der Beispielprogramme Gorillas und Nibbles, die von Microsoft geschrieben und dem Originalprodukt beigelegt waren. Darüber hinaus enthält QB64 eine Entwicklungsumgebung, die der QBasic-Entwicklungsumgebung ähnelt. QB64 erweitert auch die QBASIC-Programmiersprache um 64-Bit-Datentypen, bessere Sound- und Grafikunterstützung und bessere Anbindung an Betriebssystemfunktionen. Es kann auch einige DOS/x86-spezifische Funktionen wie Mauszugriff über den Interrupt 33h und mehrere Timer emulieren.

QB64 unter Linux

Meistens arbeite ich an einem Linux-Rechner und was liegt da näher, als QB64 auch hier zu verwenden? Das Programm ist kostenlos, OpenSource – und es lässt sich klaglos sowohl auf den 64-Bit-, als auch auf den 32-Bit-Versionen der gängigen Linux-Distributionen kompilieren. In diesem Tutorial zeige ich dir, wie man QB64 unter Debian 12 Linux (aka „Bookworm“) installiert.

Quellcode besorgen und QB64 compilieren

QB64 existiert derzeit in zwei Versionen. Während die ursprüngliche Originalversion nur noch sporadisch aktualisiert wird (Version 2.02), gibt es auch noch einen wesentlich aktuelleren Branch, die „Phoenix Edition“ mit einem erweiterten Befehlssatz, die (Stand 03/2025) noch aktiv weiterentwickelt wird. Beide haben ihre Vor- und Nachteile. Die ursprüngliche Version zeichnet sich durch schnellere Compilerzeiten mit vergleichsweise langsamem Programmcode aus, während die Phoenix Edition den Quellcode deutlich langsamer übersetzt, dafür aber hochoptimierte, schnelle Programme erzeugt. Es bleibt dir selbst überlassen, welcher Version du den Vorzug gibst.

Der Quellcode zu QB64 ist frei zugänglich für jedermann auf GitHub verfügbar.
Alte Original-Version: https://github.com/QB64Team/qb64
Phoenix Edition: https://github.com/QB64-Phoenix-Edition/QB64pe

Um darauf zugreifen zu können, musst du auf deiner Linux-Maschine zunächst ein paar Vorbereitungen treffen:

# 1. git installieren:
sudo apt install git
# 2. Verzeichnis für Quellcodes einrichten:
mkdir ~/git
# 3. Verzeichnis betreten:
cd ~/git
# 4. QB64 Quellcode abrufen:
# Original-Version: 
git clone https://github.com/QB64Team/qb64.git
# oder Phoenix Edition: 
git clone https://github.com/QB64-Phoenix-Edition/QB64pe.git
# Hinweis: Wenn du dich für die Phoenix Edition entscheidest, dann solltest 
# du zusätzlich das Paket kdialog installieren - andernfalls musst du beim 
# Laden und Speichern von Quellcode Pfad und Programmname umständlich in 
# einer Shell eingeben!
  sudo apt install kdialog

Das Herunterladen kann ein Weilchen dauern. Sobald der Download beendet ist, kannst du QB 64 compilieren. Eventuell fehlende Pakete und Abhängigkeiten werden dabei automatisch nachinstalliert. Die weitere Vorgehensweise bleibt für beide Versionen die Gleiche:

# 5. Wechsle in das qb64-Verzeichnis:
# Original-Version:
cd qb64
# oder Phoenix Edition:
cd QB64pe
# 6. Starte die Übersetzung:
./setup_lnx.sh
# 7. Warteschleife... Programm wird übersetzt.
# Koch dir ein Käffchen oder wende dich deinem Haustier zu...

Sobald der Compiler fertig ist, öffnet sich die Entwicklungsumgebung von QB64. Das Installations-Script hat übrigens automatisch eine Verknüpfung in deiner Startleiste angelegt! Du findest QB64 künftig unter Entwicklung->QB64 Programming IDE und kannst somit jederzeit mit dem Programmieren in BASIC loslegen. 😉

 

Ein Testprogramm zur Geschwindigkeitsmessung

' ----------------------------------
' -- loop.bas                     --
' -- Laufzeitmessung Do-Loop      --
' --                              --
' -- Windows 10 64-Bit            --
' -- QB64 Benchmark:              --
' -- 689647 loops, 4.23 sec.      --
' --                              --
' -- Phoenix Edition Benchmark:   --
' -- 689647 loops, 2.14 sec.      --
' --                              -- 
' -- Windows 10 WSL2 Debian Linux -- 
' -- QB64 Benchmark:              -- 
' -- 689647 loops, 5.33 sec.      -- 
' --                              -- 
' -- Phoenix Edition Benchmark:   -- 
' -- 689647 loops, 4.45 sec.      --
' --                              --
' -- Testrechner:                 --
' -- Intel Core I7 @3.60 GHz      --
'-----------------------------------
Cls
Randomize Timer
zahl1 = 100
count = 0
an = Timer ' Zeitmessung starten

Do
  zahl1 = zahl1 + 1.6
  count = count + 1
  Print Using "######"; count;
  Print ": ";
  Print Using "#######.##"; zahl1
Loop Until zahl1 > 1111110

aus = Timer ' Zeitmessung beenden
secs = (aus - an) ' Laufzeit (Sekunden) berechnen
mins = secs / 60.0
hours = mins / 60.0

' -- Laufzeit ausgeben --
Print
Print "Runtime: ": Print
Print Using "#######.##"; secs;
Print " Sekunden"
Print Using "#######.##"; mins;
Print " Minuten"
Print Using "#######.##"; hours;
Print " Stunden"
End

Programmieren mit QB64/QBasic – Links zu Tutorials und Foren

Vielleicht hast du ja Lust auf Retro-Programming mit BASIC und QB64 bekommen? Hier habe ich einige hilfreiche Links zusammengetragen, die dir beim Einstieg und der täglichen Arbeit nützlich sein können:

SelfQB – ein online-Tutorial für Einsteiger
Lerne QuickBasic kennen und arbeite dich in die Programmierung ein!

QBasic-Tutorial von Claus-Dieter Volko
mit 43 Beispielprogrammen und 8 Hausaufgaben mit Lösungen.

Programmieren in QBasic
ein weiterer guter Einsteiger-Kurs, der sich vor allem an Schüler wendet.

QBasic-Kurs für Gymnasien
Kleiner Qbasic-Einsteigerkurs auf 13 Seiten. Hierbei handelt es sich um eine Zusammenfassung eines 8-stündigen QBasic-Programmierkurses am Gymnasium Wolbeck.

„Basic lernen“ – 8-teiliges Online-Tutorial
Exzellentes QBasic-Tutorial, das systematisch in die wichtigsten Funktionen und Befehle von QBasic einführt. Liebevoll aufbereitet, mit vielen Programmbeispielen. Auch für absolute Neueinsteiger ideal geeignet.

Modernes QuickBasic
ein Tutorial für Fortgeschrittene und Profis in der QB- Programmierung
Dieser Kurs füllt eine Lücke – ein Tutorial, das viele Fragen von fortgeschrittenen Programmierern beantwortet und diesen wertvolle Tipps gibt. Der bunte Themenreigen spannt sich von der Interrupt- Programmierung über das modulare Programmieren mit MAKE-Modulen und INCLUDE-Dateien bis hin zur Programmierung einer eigenen Scriptsprachen- Interpreters mit QB.

Die QB Monster FAQ
In dieser FAQ (Frequently Asked Questions) sind all die Fragen gesammelt und beantwortet, die seit Jahren hundertfach in allen QBasic-Foren weltweit gestellt werden. Die FAQ umfasst 1028 Fragen mit über 2000 Antworten.

QB64.com
englischsprachiges Forum rund um QB64

QB64 Wiki
englischsprachige Befehlsübersicht zu QBasic/QB64

Phoenix Edition QB64 Tutorial
ein englischsprachiges Tutorial zur Spieleprogrammierung mit QB64 „Phoenix Edition“

Das war’s dann auch erst mal zu Retro-Programming mit QBasic und QB64 unter Linux. Schau gern auch mal bei meinen anderen Tutorials rein!

War dir dieses Tutorial hilfreich? Dann freue ich mich über einen kleinen Obolus für meine IT-Kasse! 🙂