Tutorial
Variable Parameterlisten
von MOD | Seite 1 von 4 |
Allgemeine Grundlagen
Meistens weiß man, wie viele Parameter eine Funktion erhalten soll, manchmal weiß man das allerdings nicht. Für den zweiten Fall kann man in einigen Fällen mit Überladung noch nachhelfen, doch wenn es absolut keine Regel für die Parameter gibt, dann hilft auch das nicht.
Ein Beispiel dafür wäre z. B. der interne Print-Befehl.
Print 1, 2, 3, 4
Print 1, 2, 3, 4, 5
Print "1", "zwei", 3.00
Dem Befehl ist die Anzahl und die Art der Parameter in den meisten Fälle ziemlich egal. Möchten wir nun eine ähnlich funktionierende Funktion erstellen, bietet FreeBASIC dafür eine Lösung.
Folgende Befehle sind hierbei wichtig:
CDECL definiert, in welcher Reihenfolge die Parameter im Speicher abgelegt werden. Standardmäßig verwendet FreeBASIC hier STDCALL, für eine variable Parameterliste muss aber zwingend CDECL angegeben werden, da es sonst zu einer Fehlermeldung kommt.
Um einfach mal in die Thematik einzutauchen, brauchen wir ein Beispiel, bei dem eine variable Parameterliste nötig sein könnte. Nicht gerade hilfreich, dafür aber sehr verständlich wäre eine Funktion, die einige Zahlen entgegennimmt und die Summe zurückliefert.
Function add Cdecl (anzahl As Integer, ...) As Integer
Dim As Integer summe
Dim As Any Ptr argument = va_first()
For i As Integer = 1 To anzahl
summe += va_arg(argument, Integer)
argument = va_next(argument, Integer)
Next
Return summe
End Function
Print add(2, 3, 5)
Sleep
Die Erklärung der Befehle folgt gleich, doch probiert erstmal diesen Code aus, denn hier fällt schon beim Starten auf, 2+3+5 ist nicht 8. Was ist also passiert?
Wie man in der ersten Zeile sieht, ist der erste Parameter fest vorgegeben, dieser ist aber nicht der erste Wert, der addiert werden soll, es handelt sich dabei um einen Parameter, der die Anzahl der folgenden Parameter vorgibt. Das hat zwei Gründe.
Bei einer variablen Parameterliste muss mindestens ein Parameter vorgegeben werden. Der zweite Grund ist, dass die im Speicher liegenden Parameter nicht direkt bekannt sind. Somit ist auch nicht erkennbar, wann die Liste endet.
Nun gibt es eben die Möglichkeit, den ersten Parameter dazu zu missbrauchen, wie viele Parameter gelesen werden sollen oder man definiert eine Endbedingung. Ein Beispiel könnte sein: "Lese solange ein, bis Zahl = 0".
Function add Cdecl (wert1 As Integer, ...) As Integer
Dim As Integer summe
Dim As Integer zahl = wert1
Dim As Any Ptr argument = va_first()
While zahl <> 0
summe += zahl
zahl = va_arg(argument, Integer)
argument = va_next(argument, Integer)
Wend
Return summe
End Function
Print add(2, 3, 5, 0)
Sleep
Ob man nun die Anzahl angibt oder eine Endbedingung definiert ist oft nur Geschmackssache. Sobald die Parameter allerdings verschiedene Datentypen enthalten, muss anders vorgegangen werden, dazu aber später mehr.
Jetzt haben wir ein paar Beispiele gesehen, doch was machen nun die einzelnen Befehle? Fangen wir von oben an:
Dim As Any Ptr argument = va_first()
Hier wird zunächst die Adresse des ersten variablen Parameters gesichert.
summe += va_arg(argument, Integer)
VA_ARG nimmt nun diese Adresse und definiert, dass sich an dieser Stelle eine Zahl vom Typ Integer befindet und gibt diese zurück. Der Typ muss angegeben werden, da anhand der Adresse nicht erkannt werden kann, was für Daten dort gespeichert wurden. Also muss der Programmierer dem Programm sagen, dass er dort einen bestimmten Typ erwartet und das Programm diese als solche interpretieren soll.
argument = va_next(argument, Integer)
Zuletzt wird die Adresse aktualisiert. Dafür muss auch hier der Typ angegeben werden, damit die Funktion weiß, wie weit sie zur nächsten Adresse springen soll.
Da ich vorhin erwähnt hatte, dass mindestens ein Parameter vorgegeben sein muss, es können natürlich auch mehr vorgegeben werden. Hier ein Beispiel:
Function add Cdecl (anzahl As Integer, operand As String, ...) As String
Dim As String ergebnis
Dim As Any Ptr argument = va_first()
For i As Integer = 1 To anzahl
Select Case operand
Case "+"
ergebnis += *va_arg(argument, ZString Ptr)
Case Else
ergebnis = *va_arg(argument, ZString Ptr)
End Select
argument = va_next(argument, ZString Ptr)
Next
Return ergebnis
End Function
Print add(2, "+", "Hallo ", "Welt!")
Sleep
Was allerdings nicht geht ist, dass man die variable Parameterliste zwischen vorgegebene legt, also in etwa so:
Function add Cdecl (anzahl As Integer, ..., operand As String) As String
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|