Buchempfehlung
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Mikrocomputertechnik mit Controllern der Atmel AVR-RISC-Familie
Umfassend, aber leicht verständlich führt dieses Buch in die Programmierung von ATMEL AVR Mikrocontrollern ein. [Mehr Infos...]
FreeBASIC-Chat
Es sind Benutzer im FreeBASIC-Chat online.
(Stand:  )
FreeBASIC bei Twitter
Twitter FreeBASIC-Nachrichten jetzt auch über Twitter erhalten. Follow us!

Referenz - Parameterübergabe

Referenz-Navigation

 

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 BefehlsreferenzeintragDECLARE. 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 BefehlsreferenzeintragBYVAL- und BefehlsreferenzeintragBYREF-Ü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 Befehlsreferenzeintrag-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 BefehlsreferenzeintragArrays 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 BefehlsreferenzeintragUDTs 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 BefehlsreferenzeintragSHARED und BefehlsreferenzeintragGültigkeitsbereich von Variablen.


Zusätzliche Informationen und Funktionen
  • Der Referenzeintrag wurde am 06.08.2007 von Redakteurytwinky angelegt.
  • Die aktuellste Version wurde am 10.04.2016 von Redakteurnemored gespeichert.
  Versionen Versionen