Arbeiten mit variablen langen Argumentlisten (Update)

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Arbeiten mit variablen langen Argumentlisten (Update)

Beitrag 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:
Zuletzt geändert von mk-soft am 22.03.2009 19:27, insgesamt 10-mal geändert.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag 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
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag 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:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
Leonhard
Beiträge: 602
Registriert: 01.03.2006 21:25

Beitrag 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.
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag 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:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Habe alles noch mal überarbeitet. Den Code reduziert und schneller.
Sollte jetzt fertig sein

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
mk-soft
Beiträge: 3845
Registriert: 24.11.2004 13:12
Wohnort: Germany

Beitrag von mk-soft »

Update v1.04

Kompatible für 32 und 64 Bit Compiler

FF :wink:
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag 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?
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7028
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Beitrag 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 ...
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Benutzeravatar
ts-soft
Beiträge: 22292
Registriert: 08.09.2004 00:57
Computerausstattung: Mainboard: MSI 970A-G43
CPU: AMD FX-6300 Six-Core Processor
GraKa: GeForce GTX 750 Ti, 2 GB
Memory: 16 GB DDR3-1600 - Dual Channel
Wohnort: Berlin

Beitrag 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:
PureBasic 5.73 LTS | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Nutella hat nur sehr wenig Vitamine. Deswegen muss man davon relativ viel essen.
Bild
Antworten