Seite 1 von 2

Arbeiten mit variablen langen Argumentlisten (Update)

Verfasst: 19.05.2007 17:35
von mk-soft
Habe mich letztens wieder etwas mit C und va_list beschäftigt und teilweise in Purebasic umgesetzt.

Update v1.05 für 32 und 64 Bit

- neu: Alle Argumente jetzt als Pointer übergeben
- neu: va_exist(zeiger) - ob parameter existiert
- neu: va_arg_integer(zeiger)

Beispiel (Update v1.05)

Code: Alles auswählen


;EnableExplicit

IncludeFile "valistHelper.pb"

; ***************************************************************************************

;-Beispiel für Addition

Procedure add(args)

  Protected zahl, zahlen
  
  ; Init Arguments
  va_list(zeiger)
  ; Zeiger auf das erste Argument setzen
  va_start(zeiger)
  
  While va_exist(zeiger)
    zahl = va_arg_long(zeiger)
    zahlen + zahl
  Wend
  
  ProcedureReturn zahlen
  
EndProcedure

; ***************************************************************************************

;-Beispiel für Addition mit übergabe der Anzahl von Argumenten

Procedure addition(anzahl, args)

  Protected zahl, zahlen, index
  
  ; Init Arguments
  va_list(zeiger)
  ; Zeiger auf das erste Argument setzen
  va_start(zeiger)
  
  For index = 1 To anzahl
    zahlen + va_arg_long(zeiger)
  Next
  
  ProcedureReturn zahlen
  
EndProcedure

; ***************************************************************************************

;-Beispiel für Text
; Da Purebasic den Type Any nicht kennt muss der Text als Zeiger "@" übergeben werden

Procedure.s concat(args)

  Protected text.s, result.s
  
  ; Init Arguments
  va_list(zeiger)
  ; Zeiger auf das erste Argument setzen
  va_start(zeiger)
  
  While va_exist(zeiger)
    text = va_arg_string(zeiger)
    result + text
  Wend
  
  ProcedureReturn result
  
EndProcedure

; ***************************************************************************************

;-Beispiel für Variant

Procedure AnyVariant(args)

  Protected *variant.variant , zahlen, text.s
  
  ; Init Arguments
  va_list(zeiger)
  ; Zeiger auf das erste Argument setzen
  va_start(zeiger)
  
  While va_exist(zeiger)
    *variant = va_arg_variant(zeiger)
    If *variant = 0
      Break
    EndIf
    Select *variant\vt
      Case #VT_BSTR
        text + PeekS(*variant\bstrVal, #PB_Any, #PB_Unicode)
      Case #VT_I4, #VT_UI4
        zahlen + *variant\lVal
        
    EndSelect
  Wend
  
  Debug "Text: " + text
  Debug "Summe: " + Str(zahlen)
  
EndProcedure

; ***************************************************************************************

; ***************************************************************************************

; UNICODE / ASCII Helper for SysAllocString
Procedure helpSysAllocString(*Value)
  ProcedureReturn SysAllocString_(*Value)
EndProcedure
Prototype.l ProtoSysAllocString(Value.p-unicode)

;-T_BSTR
Global T_BSTR.ProtoSysAllocString = @helpSysAllocString()

; ***************************************************************************************

Define.l x,y,z
Define.s a,b,c,d

Debug "Test Addition"

x = 20
y = 80
z = 100
a1 = 0
a2 = 20
a3 = 30
a4 = 40
a5 = 50

Debug add(@x,@y)

Debug add(@a1, @a2, @a3, @a4, @a5)

Debug "Test Concat (Text)"
Debug concat(@"Hallo ", @"Welt")
a.s = "Das "
b.s = "ist "
c.s = ""
d.s = "ein Test"
Debug concat(@a,@b,@c,@d)

Debug "Test Variant"
Define.variant val1, val2, val3, val4
val1\vt = #VT_I4
val1\lVal = 100
val2\vt = #VT_I4
val2\lVal = 200
val3\vt = #VT_BSTR
val3\bstrVal = T_BSTR("Hallo Welt. ")
val4\vt = #VT_BSTR
val4\bstrVal = T_BSTR(":)")

AnyVariant(val1, val2, val3, val4)
valistHelper.pb (Update v1.05 für 32 und 64 Bit Compiler)

Code: Alles auswählen

;-TOP
; Kommentar     : Arbeiten mit variablen langen Argumentlisten
; Author        : mk-soft
; Second Author : 
; Datei         : valistHelper.pb
; Version       : 1.05
; Erstellt      : 19.05.2007
; Geändert      : 22.03.2009
; 
; Compilermode  :
;
; ***************************************************************************************

;- Declaration, Funktionen und Macros

; Argumentenliste
Macro args
  *__a = 0, *__b = 0, *__c = 0, *__d = 0, *__e = 0, *__f = 0, *__g = 0, *__h = 0, *__i = 0, *__j = 0, *__k = 0, *__l = 0
EndMacro

; Macro zur Initialisierung
Macro va_list(zeiger)
  Define.integer zeiger
EndMacro

; Procedure gibt aktuellen Zeiger zurück und setzt auf das nächste Argument
Procedure va_next(*zeiger.integer)
  *zeiger\i + SizeOf(*zeiger)
  ProcedureReturn *zeiger\i - SizeOf(*zeiger)
EndProcedure

; Macro zum setzen auf das erste Argument
Macro va_start(zeiger)
  zeiger\i = @*__a
EndMacro

Macro va_exist(zeiger)
  PeekI(zeiger\i)
EndMacro

; Macros und Funktionen zum auslesen der Arguemnte

Macro va_arg_integer(zeiger)
  PeekI(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_quad(zeiger)
  PeekQ(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_long(zeiger)
  PeekL(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_word(zeiger)
  PeekW(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_byte(zeiger)
  PeekB(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_double(zeiger)
  PeekD(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_float(zeiger)
  PeekF(PeekI(va_next(zeiger)))
EndMacro

Macro va_arg_variant(zeiger)
  PeekI(va_next(zeiger))
EndMacro

Procedure.s va_arg_string(*zeiger)
  Protected *pstr
  *pstr = PeekI(va_next(*zeiger))
  If *pstr
    ProcedureReturn PeekS(*pstr)
  Else
    ProcedureReturn ""
  EndIf
EndProcedure

Procedure.c va_arg_chr(*zeiger)
  Protected *pstr
  *pstr = PeekI(va_next(*zeiger))
  If *pstr
    ProcedureReturn PeekC(*pstr)
  Else
    ProcedureReturn 0
  EndIf
EndProcedure

; ***************************************************************************************
Die Argumente müssen als Zeiger "@" übergeben werden (PB-Intern)

FF :wink:

Verfasst: 19.05.2007 17:45
von ts-soft
:allright:
Bin ein wenig erstaunt das PB nicht meckert, weil die Parameteranzahl ja
nicht stimmt :freak:

Kann man Text und Longs auch mixen? Mit Erkennung?

Gruß
Thomas

Verfasst: 19.05.2007 17:52
von mk-soft
PB meckert deswegen nicht weil ja args durch den Macro ersetzt wird.

Man kann Text und Longs mixen. Aber das mit der automatischen Erkennung geht nicht.
Vielleicht wie bei den DispHelper vorher ein String übergeben mit den Identifer für die Argumente.

FF :wink:

Verfasst: 19.05.2007 17:54
von Leonhard
ts-soft hat geschrieben:Bin ein wenig erstaunt das PB nicht meckert, weil die Parameteranzahl ja
nicht stimmt :freak:
Die Parameter sind
*__a = 0, *__b = 0, *__c = 0, *__d = 0, *__e = 0, *__f = 0, *__g = 0, *__h = 0, *__i = 0, *__j = 0, *__k = 0, *__l = 0
und dadurch stimmt die anzahl der Parameter. Siehe Macro.
Kann man Text und Longs auch mixen? Mit Erkennung?
Hier hast du´s gemischt:

Code: Alles auswählen

Procedure concat_X(args)

  Protected zeiger, text.s, result.s, zahl, zahlen

  ; Zeiger auf das erste Argument setzen
  va_start(zeiger)
 
  Repeat
    text = va_arg_string(zeiger)
    result + text
    
    zahl = va_arg_long(zeiger)
    zahlen + zahl
  Until text = ""
 
 Debug "Text: "+result
 Debug "Zahl: "+Str(zahlen)
EndProcedure
Wenn du es durcheinander meinst, geht das nicht, da man den unterschied zwischen String und Long schwer aus dem Speicher lesen kann. Da müsste man eine Variant-Struktur nehmen.

Verfasst: 19.05.2007 18:14
von mk-soft
Kleines Beispiel mit gemischten Argumenten.

Code: Alles auswählen

IncludeFile "valistHelper.pb"

Procedure test(argument.s, args)

  Protected index, type.s
  
  va_list(zeiger)
  va_start(zeiger)
  Repeat
    index + 1
    type = StringField(argument, index, ",")
    Select type
      Case "f" : Debug "Float: " + StrF(va_arg_float(zeiger))
      Case "d" : Debug "Double: " + StrD(va_arg_double(zeiger))
      Case "q" : Debug "Quad: " + StrQ(va_arg_quad(zeiger))
      Case "l" : Debug "Long: " + Str(va_arg_long(zeiger))
      Case "s" : Debug "String: " + va_arg_string(zeiger)
    EndSelect
  Until type = ""
EndProcedure



test("l,l,s", 100, 200, @"Hallo")

x.f = 100.4
y.d = 200.5
z.q = 123456789000
test("f,d,q,s", @x,@y, @z, @"Hallo Welt")
FF :wink:

Verfasst: 20.05.2007 17:22
von mk-soft
Habe alles noch mal überarbeitet. Den Code reduziert und schneller.
Sollte jetzt fertig sein

FF :wink:

Verfasst: 22.03.2009 16:11
von mk-soft
Update v1.04

Kompatible für 32 und 64 Bit Compiler

FF :wink:

Verfasst: 22.03.2009 16:43
von ts-soft

Code: Alles auswählen

EnableExplicit

IncludeFile "valistHelper.pb"

Procedure add(args)

  Protected zahl, zahlen
 
  ; Init Arguments
  va_list(zeiger)
  ; Zeiger auf das erste Argument setzen
  va_start(zeiger)
 
  Repeat
    zahl = va_arg_long(zeiger)
    zahlen + zahl
  Until zahl = 0
 
  ProcedureReturn zahlen
 
EndProcedure

Debug add(10, 10, 10)
Debug add(0, 10, 10)
Der zweite Debug funktioniert nicht?

Verfasst: 22.03.2009 16:44
von STARGÅTE
wie auch, die Proceduer ist ja falsch:

Code: Alles auswählen

Repeat 
    zahl = va_arg_long(zeiger) 
    zahlen + zahl 
Until zahl = 0
er hört ja gleich auf ...

Verfasst: 22.03.2009 17:07
von ts-soft
Die Include kann ja die Anzahl Parameter nicht feststellen, ist so IMHO
etwas sinnlos.
Entweder die ermittelt die Anzahl irgendwie oder man muß die Anzahl mit
übergeben, auf 0 oder irgendeinen anderen Wert verlassen geht garnicht :mrgreen: