Tutorial
Variable Parameterlisten
von MOD | Seite 4 von 4 |
Wichtige Hinweise
Bis einschließlich der Version 0.21.1 des Compilers gibt es einen Fehler der auftritt, wenn der erste Parameter der Funktion ein (U)Byte oder (U)Short ist. Diese Datentypen nehmen weniger als 4 Byte im Speicher ein. Durch den Fehler ergab sich ein Versatz der Adressen, da statt der wahren Größe immer 4 Byte angenommen wurden.
So führt folgender Code bis zur besagten Version zu falschen Ergebnissen:
Sub PrintInt Cdecl (anzahl As Byte, ...)
Dim As Any Ptr argument = va_first()
For a As Integer = 1 To anzahl
Print va_arg(argument, Integer)
argument = va_next(argument, Integer)
Next
End Sub
Dim As Integer zahl1
Dim As Integer zahl2
zahl1 = 123
zahl2 = 456
PrintInt(2, zahl1, zahl2)
Sleep
Gerade beim Umgang mit Strings oder UDTs kann es durch diesen Fehler auch zu Abstürzen kommen.
Um den Fehler zu umgehen, muss dafür gesorgt werden, dass der erste Parameter 4 Byte lang ist. Man kann also schlicht Integer verwenden oder aber den Parameter ByRef übergeben. Das bewirkt, dass intern eine Adresse übergeben wird und nicht der Wert. Adressen sind immer 4 Byte-Werte, da FreeBASIC ein 32bit-Compiler ist, was wieder zur richtigen Anzahl an Bytes führt. Die Lösung könnte also so aussehen:
Sub PrintInt Cdecl (ByRef anzahl As Byte, ...)
Dim As Any Ptr argument = va_first()
For a As Integer = 1 To anzahl
Print va_arg(argument, Integer)
argument = va_next(argument, Integer)
Next
End Sub
Dim As Integer zahl1
Dim As Integer zahl2
zahl1 = 123
zahl2 = 456
PrintInt(2, zahl1, zahl2)
Sleep
Nicht empfehlenswert ist die folgende Methode, die ich nur als Nachweis für den Verschub aufzeige.
Sub PrintInt Cdecl (anzahl As Byte, ...)
Dim As Any Ptr argument = va_first() + 3 ' 1 Byte + 3 Byte = 4 Byte -> der Verschub wird so wieder berichtigt
For a As Integer = 1 To anzahl
Print va_arg(argument, Integer)
argument = va_next(argument, Integer)
Next
End Sub
Dim As Integer zahl1
Dim As Integer zahl2
zahl1 = 123
zahl2 = 456
PrintInt(2, zahl1, zahl2)
Sleep
Variable Parameter und Überladung
In diesem Zusammenhang wäre auch eine Überladung der Funktionen interessant, wenn man z. B. neben einer reinen Integer-Methode auch eine spezielle für Double oder Strings haben möchte.
Leider ist es momentan (Version 0.21.1) nicht möglich, einer überladenen Funktion eine variable Parameterliste zu spendieren. Dies könnte sich in Zukunft allerdings ändern.
Aus diesem Grund zeige ich hier an zwei Code-Beispielen auf, wie das zukünftig aussehen könnte. Gezeigt wird eine normale Funktionsvariante und eine objektorientiere Lösung.
Declare Function add Cdecl OverLoad (anzahl As Integer, ...) As String
Declare Function add Cdecl (anzahl As String, ...) As String
Function add Cdecl (anzahl As Integer, ...) As String
Dim As String ergebnis
Dim As Any Ptr argument = va_first()
For i As Integer = 1 To anzahl
ergebnis += *va_arg(argument, ZString Ptr)
argument = va_next(argument, ZString Ptr)
Next
Return ergebnis
End Function
Function add Cdecl (anzahl As String, ...) As String
Dim As String ergebnis
Dim As Any Ptr argument = va_first()
For i As Integer = 1 To ValInt(anzahl)
ergebnis += *va_arg(argument, ZString Ptr)
argument = va_next(argument, ZString Ptr)
Next
Return ergebnis
End Function
Print add(2, "Hallo ", "Welt!")
Print add("2", "Hallo ", "Welt!")
Sleep
Type myType
Declare Function add Cdecl (anzahl As Integer, ...) As String
Declare Function add Cdecl (anzahl As String, ...) As String
dummy As Integer
End Type
Function myType.add Cdecl (anzahl As Integer, ...) As String
Dim As String ret
Dim As Any Ptr argument = va_first()
For i As Integer = 1 To anzahl
ergebnis += *va_arg(argument, ZString Ptr)
argument = va_next(argument, ZString Ptr)
Next
Return ergebnis
End Function
Function myType.add Cdecl (anzahl As String, ...) As String
Dim As String ergebnis
Dim As Any Ptr argument = va_first()
For i As Integer = 1 To ValInt(anzahl)
ergebnis += *va_arg(argument, ZString Ptr)
argument = va_next(argument, ZString Ptr)
Next
Return ergebnis
End Function
Dim As myType test
Print test.add(2, "Hallo ", "Welt!")
Print test.add("2", "Hallo ", "Welt!")
Sleep
Wie erwähnt, diese Codes sind momentan nicht lauffähig.
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|