Referenz - Parameterübergabe
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: die direkte Übergabe in der Parameterliste der Prozedur oder die Globalisierung der Variable.
Direkte Übergabe in der Parameterliste der Prozedur
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
DIM 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
DIM c AS BYTE, d AS INTEGER
foo c, a, b
d = bar(c, a, b)
SLEEP
'---------------'
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, 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. Auch wenn der Wert der übergebenen Variablen innerhalb der Prozedur verändert wird, bleibt er in der aufrufenden Prozedur unverändert. 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.
Anmerkung:
Standardmäßig werden Zahlendatentypen (INTEGER, DOUBLE usw.) BYVAL übergeben, STRINGs und UDTs dagegen BYREF. Arrays werden immer BYREF übergeben; eine Änderung der Übergabemethode ist hier nicht möglich. Wenn das Programm mit der Kommandozeilenoption -lang deprecated oder -lang qb compiliert wird, verwendet der Compiler die Übergabemethode, die bis einschließlich FreeBASIC v0.16 verwendet wurde: alle Parameter werden dann standardmäßig BYREF übergeben.
Beispiel:
DECLARE SUB foobar (BYREF a, BYVAL b)
a = 10
b = 5
PRINT "Vor dem Prozeduraufruf:"
PRINT a, b
PRINT
foobar a, b
PRINT
PRINT "Nach dem Prozeduraufruf:"
PRINT a, b
SLEEP
SUB foobar (BYREF a, BYVAL b)
PRINT "Beginn der Prozedur:"
PRINT a, b
PRINT
a = 20
b = 40
PRINT "Ende der Prozedur:"
PRINT a, b
END SUB
Ausgabe:
Vor dem Prozeduraufruf:
10 5
Beginn der Prozedur:
10 5
Ende der Prozedur:
20 40
Nach dem Prozeduraufruf:
20 5
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
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
Ausgabe:
7 6
22 14
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.
Arrays
Function und Sub können neben Variablen auch Arrays als Parameter verwenden:
' SUB mit einem Integer-Array als Parameter
Declare Sub unsicher (array() As Integer)
Declare Sub sicher (array() As Integer)
' zweidimenionales Array mit 8 * 5 Feldern (beginnend ab 0!)
Dim As Integer meinArray(7, 4)
' Beispielwerte
meinArray(2, 2) = 2
meinArray(4, 4) = 4
' Aufruf der Sub - beim Array sind die Klammern () nötig um Arrayzugriff zu signalisieren
unsicher(meinArray())
Print "----"
' Aufruf der sicheren Sub, bei der auf den Zugriff geachtet wird
sicher(meinArray())
Sleep ' auf Tastendruck warten
Sub unsicher (array() As Integer)
' Mit UBOUND lässt sich die Obergrenze ermitteln
' Problem dabei: es wird nur die Obergrenze der ersten Dimension abgefragt
For i As Integer = 0 To UBound(array)
Print array(i,i) '*
Next
' * Hier ist Vorsicht geboten, da ein Arrayzugriff außerhalb des
' gültigen Bereichs unvorhersagbare Werte ergeben und sogar bis
' zum Programmansturz führen kann!
End Sub
Sub sicher (array() As Integer)
' Um Probleme mit der Obergrenze zu umgehen, wird auch die zweite Dimension abgefragt
For i As Integer = 0 To UBound(array)
If i <= UBound(array, 2) Then Print array(i,i) '*
Next
End Sub
TYPES (UDTs)
Auch die Übergabe von UDTs ist möglich:
Type myType
x As Integer
y As Integer
End Type
Declare Sub changeMyVar(anyVar As myType)
Dim As myType myVar
myVar.x = 5
myVar.y = 7
Print "Vorher:"
Print myVar.x
Print myVar.y
changeMyVar(myVar)
Print
Print "Nachher:"
Print myVar.x
Print myVar.y
Sleep
' UDTs werden automatisch BYREF übergeben
' Durch explizite Angabe von BYVAL kann dies aber auch verhindert werden
Sub changeMyVar(anyVar As myType)
anyVar.x += 1
anyVar.y -= 1
End Sub
Einen Parameter, der ein Array ist und vom Typ eines eigenen UDTs ist natürlich auch möglich.
Sub/Function Pointer
Neben den bisher beschriebenen, können auch Pointer auf Subs und Functions übergeben werden. Folgendes Beispiel zeigt die Verwendung auf:
Sub eineSub(parameter As Integer)
Print "eineSub", parameter
End Sub
Function eineFunction(parameter As Integer) As Integer
Print "eineFunction", parameter
Return 0
End Function
Sub foo(parameter As Sub (parameter As Integer))
parameter(1)
End Sub
Sub bar(parameter As Function (parameter As Integer) As Integer)
Print parameter(2)
End Sub
foo(@eineSub)
bar(@eineFunction)
Sleep
Ausgabe:
eineSub 1
eineFunction 2
0
Globalisierung
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 Schlüsselwort SHARED. Bei ihrer ersten Definition mit DIM oder COMMON muss nur SHARED angegeben werden, um diesen Effekt zu erzielen. Zu weiteren Details siehe SHARED und Gültigkeitsbereich von Variablen.
Zusätzliche Informationen und Funktionen | ||||
---|---|---|---|---|
|