Referenz - VA_FIRST
Syntax: VA_FIRST
Typ: Funktion
Kategorie: Speicher
VA_FIRST gibt einen Pointer auf den ersten Parameter einer variablen Parameterliste zurück.
Unter FreeBASIC ist es möglich, Prozeduren zu erstellen, die keine festgelegte Parameterliste besitzen. Diesen Prozeduren darf eine beliebig lange Parameterliste übergeben werden, und die Parameter dürfen von jedem Datentyp sein. Eine solche Liste wird variable Parameterliste genannt. Um dies zu ermöglichen, verwendet man bei DECLARE und im Prozedurheader folgende Syntax:
DECLARE {SUB|FUNCTION} (<'normaleParameter'>, ...)
'normaleParameter' ist dabei eine normale Parameterliste, wie bei DECLARE erklärt. Das '...' leitet die variable Parameterliste ein.
Bei dieser Form der Übergabe geht aber die Information verloren, um welche Datentypen es sich in der variablen Liste handelt bzw. wie viele Parameter übergeben wurden. Daher werden oft sogenannte Format-Strings in der normalen Parameterliste übergeben, in denen beschrieben wird, welche Parameter übergeben wurden. Dieser Format-String darf jedes beliebige Format besitzen, da der Programmierer die Parameterübergabe komplett selbst übernimmt. Der String muss ihm lediglich die Informationen liefern, die er braucht, um die Werte aus der variablen Parameterliste herauszulesen.
VA_ARG wird dazu benutzt, um den Wert eines Parameters zu ermitteln. VA_NEXT aktualisiert den von VA_FIRST zurückgegebenen Pointer, sodass er auf das nächste Argument der variablen Parameterliste zeigt.
Beispiel (aus dem examples-Ordner des FreeBASIC-Verzeichnisses):
' Beispiel für variable Parameter
Declare Sub myPrintf cdecl (byRef FormatierString As String, ...)
Dim s as String = "bar"
myPrintf "Integer=%i, LongInt=%l, Single=%f, Double=%d, String=%s, String=%s", _
1, 1LL shl 32, 2.2, 3.3, "foo", s
Sleep
Sub myPrintf cdecl (byRef FormatierString As String, ...)
Dim As Integer i, c
Dim As String s
Dim As Any Ptr Arg = va_first ' Pointer zum ersten variablen Argument holen
Dim As ZString Ptr p
p = StrPtr(FormatierString)
i = Len(FormatierString)
Do While i>0 ' Für jedes Zeichen in FormatierString..
c = *p
p += 1
i -= 1
' Ist es ein Formatierzeichen?
If Chr(c) = "%" Then ' Typ holen
c = *p
p += 1
i -= 1
' variables Argument ausgeben, abhängig vom Typ
Select Case Chr(c)
Case "i" ' Integer?
s = s & va_arg(Arg, Integer)
Arg = va_next(Arg, Integer)
' Anders als in C muss va_next() benutzt werden, da
' va_arg() die Pointer nicht aktualisiert
Case "l" ' LongInteger? (64-bit)
s = s & va_arg(Arg, LongInt)
Arg = va_next(Arg, LongInt)
Case "f", "d"
' Single oder Double? (Beachte: wegen der C-ABI werden alle Singles, die
' übergeben wurden, in Doubles konvertiert)
s = s & va_arg(Arg, Double)
Arg = va_next(Arg, Double)
Case "s" ' String?
' Strings werden byVal übergeben, also ist ihre Länge unbekannt
s = s & *va_arg(Arg, ZString Ptr)
Arg = va_next(Arg, ZString Ptr)
End Select
Else ' normales Zeichen, einfach ausgeben..
s = s & Chr( c )
End If
Loop
Print s;
End Sub
Beispiel 2 (verkürzte Variante):
Sub myPrint Cdecl (FormatierString As String, ...)
Dim As Any Ptr argument = va_first
Dim As Integer i
Dim As ZString Ptr p
For i = 1 To Len(FormatierString)
Select Case Mid(FormatierString, i, 1)
Case "i"
Print "Integer: " & va_arg(argument, Integer)
argument = va_next(argument, Integer)
Case "l"
Print "LongInt: " & va_arg(argument, LongInt)
argument = va_next(argument, LongInt)
Case "f", "d"
Print "Double: " & va_arg(argument, Double)
argument = va_next(argument, Double)
Case "s"
Print "String: " & *va_arg(argument, ZString Ptr)
argument = va_next(argument, ZString Ptr)
End Select
Next
End Sub
'###############################################################
Dim s As String = "String2"
myPrint( "ilfdss", 1, 4294967296, 1.2, 3.4, "String1", s )
Sleep
Hinweis:
Eine SUB/FUNCTION, die eine variable Parameterliste verwendet, muss zwingend mit CDECL deklariert werden. Ansonsten meldet der Compiler einen Fehler.
Unterschiede zu QB: neu in FreeBASIC
Plattformbedingte Unterschiede:
VA_FIRST wird nicht unterstützt, wenn mit der Compileroption '-gen gcc' compiliert wird. Für plattformübergreifende Kompatibilität verwenden Sie die Funktionen zum Umgang mit CVA_LIST.
Unterschiede unter den FB-Dialektformen:
In der Dialektform -lang qb steht VA_FIRST nicht zur Verfügung und kann nur über __VA_FIRST aufgerufen werden.
Siehe auch:
VA_ARG, VA_NEXT, CVA_START, CVA_COPY, CVA_ARG, CVA_END, DECLARE, SUB, FUNCTION, CDECL, Datentypen, ... (Auslassung[Ellipsis]), Prozeduren
Zusätzliche Informationen und Funktionen | ||||
---|---|---|---|---|
|