Buchempfehlung
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
Windows-Programmierung. Das Entwicklerhandbuch zur WIN32-API
"Der" Petzold, das über 1000 Seiten starke Standardwerk zum Win32-API - besonders nützlich u. a. bei der GUI-Programmierung in FreeBASIC! [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!

Tutorial

Variable Parameterlisten

von RedakteurMODSeite 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 BefehlsreferenzeintragByRef ü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 BefehlsreferenzeintragDouble 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.

 

Gehe zu Seite Gehe zu Seite  1  2  3  4  
Zusätzliche Informationen und Funktionen
  • Das Tutorial wurde am 06.04.2011 von RedakteurMOD angelegt.
  • Die aktuellste Version wurde am 28.08.2011 von RedakteurMOD gespeichert.
  Bearbeiten Bearbeiten  

  Versionen Versionen