FreeBasic: Parameterübergabe

Aus Wikibooks

Prozeduren können i.d.R. nicht auf den Speicher des Hauptprogramms zugreifen. Wird im Hauptprogramm eine Variable mit dem Bezeichner 'a' verwendet, ist ihr Wert im Unterprogramm nicht verfügbar, selbst wenn in diesem auch eine Variable mit dem Bezeichner 'a' verwendet wird. Um einer Prozedur Variablen zu übergeben, gibt es zwei Möglichkeiten: Direkte Übergabe in der Parameterliste der Prozedur oder Globalisierung der Variable.

Direkte Übergabe in der Parameterliste der Prozedur[Bearbeiten]

Jedes Unterprogramm muss zunächst deklariert werden; dazu verwendet man DECLARE. Die DECLARE-Anweisung enthält auch eine Parameterliste; dies ist eine Auflistung der Variablen, die an das Unterprogramm übergeben werden sollen. Dabei ist der verwendete Bezeichner nebensächlich; er kann in der Prozedur selbst unter einem ganz anderen Namen übergeben werden. Wichtig ist aber der Datentyp!

Beispiel:

 DECLARE SUB foo (a AS BYTE b AS STRING, c AS INTEGER)
 DECLARE FUNCTION bar (a AS BYTE b AS STRING, c AS INTEGER) AS INTEGER

Hier werden zwei Prozeduren definiert. Bei beiden ist der erste Parameter vom Typ BYTE, der zweite vom Typ STRING und der dritte vom Typ INTEGER. Der Rückgabetyp der FUNCTION ist Integer.

Beim Aufruf der Prozeduren können dennoch andere Bezeichner für die Variablen verwendet werden:

 DECLARE SUB foo (a AS BYTE b AS STRING, c AS INTEGER)
 DECLARE FUNCTION bar (a AS BYTE b AS STRING, c AS INTEGER) AS INTEGER
 
 DIM a AS STRING, b AS INTEGER, c AS BYTE, d AS INTEGER
 
 foo c, a, b
 d = bar(c, a, b)

Jede Prozedur hat einen "Header". Dieser enthält ähnlich wie die DECLARE-Anweisung die Parameterliste. Im Gegensatz zur DECLARE-Zeile sind die Bezeichner der Parameter hier aber von Bedeutung:

 DECLARE SUB foo (a AS BYTE b AS STRING, c AS INTEGER)
 DECLARE FUNCTION bar (a AS BYTE b AS STRING, c AS INTEGER) AS INTEGER
 
 DIM a AS STRING, b AS INTEGER, c AS BYTE, d AS INTEGER
 
 foo c, a, b
 d = bar(c, a, b)
 
 '------------------------------------------------------------------------------'
 
 SUB foo (d AS BYTE, e AS STRING, f AS INTEGER)
 PRINT e, f + d
 END SUB
 
 FUNCTION bar (e AS BYTE, z AS STRING, a AS INTEGER) AS INTEGER
 PRINT z
 bar = e * a
 END FUNCTION

Die Werte von a, b und c werden in der Reihenfolge übergeben, in der sie beim Aufruf aufgeführt sind. Innerhalb der Prozedur erhalten sie dann einen neuen Namen. In der SUB foo wird c als d, a als e und b als f bezeichnet. In der FUNCTION bar wird c als e, a als z und b als a bezeichnet.

Bei dieser Art der Übergabe unterscheidet man weiter in BYVAL- und BYREF-Übergabe. Werden die Variablen BYREF übergeben (was Standard ist), können die Prozeduren den Wert der Variablen so verändern, dass er auch im aufrufenden Programmteil geändert wird. Variablen, die BYVAL übergeben werden, erhalten eine eigene Speicherstelle in der Prozedur. Wird der Wert der übergebenen Variable verändert, bleibt ihr Wert in der aufrufenden Prozedur derselbe. Auf welche Weise die Variablen übergeben werden sollen, steht im Prozedurheader und in der DECLARE-Zeile; vor dem jeweiligen Parameter wird ein BYREF bzw. BYVAL angegeben.

Beispiel:

 DECLARE SUB foobar (BYREF a, BYVAL b)
 
 a = 10
 b = 5
 
 PRINT a, b
 PRINT
 
 foobar a, b
 PRINT
 
 PRINT a, b
 
 SUB foobar (BYREF a, BYVAL b)
   PRINT a, b
   PRINT
 
   a = 20
   b = 40
 
   PRINT a, b
 END SUB
Ausgabe:
10 5
10 5
20 40
20 5

Erwartet eine Prozedur einen STRING, so können auch Variablen anderen Typs übergeben werden; diese müssen allerdings BYVAL übergeben werden. Außerdem muss die BYVAL-Klausel auch bei der Übergabe angegeben werden:

 DECLARE SUB PrintX (BYVAL x AS STRING)
 
 PrintX "abc"
 PrintX BYVAL 0
 PrintX BYVAL 33
 
 SLEEP
 
 
 SUB PrintX (BYVAL x AS STRING)
   PRINT LEN(X)
 END SUB
Ausgabe:
3
0

Aborting due to runtime error 12 ("segmentation violation" signal)

Wie Sie sehen, tritt ein Fehler auf, sobald versucht wird, 33 zu übergeben. Das liegt daran, wie freeBASIC seine STRINGs behandelt; dies soll hier jedoch nicht erklärt werden. Wie Sie jedoch sehen, kann 0 sehr wohl übergeben werden; der Wert wird in der Prozedur dann als Nullstring behandelt.

Beim Aufruf von Prozeduren können Parameter ausgelassen werden, wenn in der DECLARE-Anweisung für diesen Parameter eine Konstante angegeben wird. Die DECLARE-Anweisung enthält dann, neben der Parameterliste, die Zuweisung der Konstanten, die nur dann benutzt werden, wenn im Aufruf an dieser Stelle kein Wert übergeben wird. Dabei ist wichtig, dass die verwendeten Bezeichner in der DECLARE-Anweisung und im Prozedur-Header gleich sind. Die Zuweisung der Konstanten muss im Prozedur-Header nicht wiederholt werden. Diese optionalen Parameter können von jedem Datentyp sein; auch STRINGs sind erlaubt. Lediglich UDTs und Arrays unterstützen diese Technik bislang nicht. Beispiel:

 DECLARE SUB plus (BYREF a AS INTEGER, BYVAL i AS INTEGER = 1)
 DECLARE FUNCTION minus (BYREF a AS INTEGER, BYVAL i AS INTEGER = 1) AS INTEGER
 DIM x AS INTEGER
 
 x = 6
 'Konstante benutzen
 plus x
 PRINT x, minus (x)
 
 'angegebenen Werte benutzen
 plus x, 15
 PRINT x, minus (x, 8)
 
 SLEEP
 END
 
 SUB plus (BYREF a AS INTEGER, BYVAL i AS INTEGER)
   a += i
 END SUB
 
 FUNCTION minus (BYREF a AS INTEGER, BYVAL i AS INTEGER) AS INTEGER
   minus = a - i
 END FUNCTION

FreeBasic selbst macht von dieser Möglichkeit Gebrauch: z.B. bei MID$(Text AS STRING, Start [, Länge]): Hier können sie eine Länge angeben, müssen dies aber nicht tun.

Oder bei GET #Dateinummer, [Position], Variable: Hier können Sie z.B. GET #1, , x schreiben und erhalten dann, von der aktuellen Position der geöffneten Datei, einen Wert in x eingelesen.

Globalisierung[Bearbeiten]

Manche Variablen werden in (fast) jedem Unterprogramm benötigt. Es wäre sehr umständlich, diese Variablen bei jedem Aufruf der Prozedur in die Parameterliste einzugeben. Stattdessen ist es möglich, einzelne Variablen allen Prozeduren zugänglich zu machen; sie werden dann so behandelt, als wären sie jedem Unterprogramm BYREF übergeben worden. Möglich ist das mit dem SHARED-Schlüsselwort.

Bei ihrer ersten Definition mit DIM oder COMMON muss nur SHARED angegeben werden, um diesen Effekt zu erzielen. Weitere Details lesen Sie bitte unter SHARED in der Referenz.