Seite 1 von 1

Übergabe Structure an Procedure, was ist besser

Verfasst: 17.06.2023 12:01
von hjbremer
Man kann Strukturvariablen an Prozeduren unterschiedlich übergeben

Wie in Beispiel 1 und es in der Hilfe steht oder wie in Beispiel 2

Was ist besser, schöner etc ?

ich persönlich bevorzuge Beispiel 2

Code: Alles auswählen

;Beispiel: Übergabe einer Struktur an eine Prozedur aus der Hilfe

  Structure Whatever
    a.l
    b.l[2]          ; Statisches Array (Standard C) mit 2 Werten b[0] und b[1], nicht in der Größe veränderbar
    
  EndStructure

  MyVar.Whatever

  Procedure MyProcedure(*blahblah.Whatever)
    *blahblah\a = 5
    *blahblah\b[0] = 1
    *blahblah\b[1] = 2
  EndProcedure

  MyProcedure(@MyVar)  ;oder MyProcedure(MyVar) @ wird nicht benötigt
  Debug MyVar\a
  Debug MyVar\b[0]
  Debug MyVar\b[1]
  
  
;Beispiel 2
  
  MyVar2.Whatever
  
  Procedure MyProcedure2(blahblah)     
    *blahblah.Whatever = blahblah     
    *blahblah\a = 15
    *blahblah\b[0] = 11
    *blahblah\b[1] = 12
  EndProcedure

  MyProcedure2(MyVar2) 
  Debug MyVar2\a
  Debug MyVar2\b[0]
  Debug MyVar2\b[1]


Re: Übergabe Structure an Procedure, was ist besser

Verfasst: 17.06.2023 12:36
von NicTheQuick
Das erste finde ich besser. Dann erkennt man direkt an der Prozedurdeklaration, dass sie einen Pointer mit der Struktur "Whatever" erwartet.

Re: Übergabe Structure an Procedure, was ist besser

Verfasst: 17.06.2023 15:12
von STARGÅTE
Also ich verwende ausschließlich Beispiel 1, also sowohl den Pointer im Prozedurargument als auch das @ bei der übergabe.
Dein zweites Beispiel hat eine Zuweisung mehr (*blahblah.Whatever = blahblah).
Außerdem fehlt hier ein Protected for "*blahblah.Whatever", um eine Kollision mit einer globalen Variable zu verhinden.
Bei der Übergabe das @ wegzulassen geht, aber verringert die Lesbarkeit des Codes.
Bei MyProcedure2(MyVar2) sieht man nicht sofort, dass MyVar2 als Referenz übergeben wird und sich daher auch ändern könnte.

Re: Übergabe Structure an Procedure, was ist besser

Verfasst: 17.06.2023 16:03
von Benubi
Die erste Variante ist die effizientere. Man kann von außen auch sehen, welcher Struktur Typ benötigt wird.

Die zweite Variante hat auch die Eigenschaft, daß Du mehr Variablen benötigst und zusätzliche Wert-Zuweisungen durchführst. Dies sind nur 3-4 Operationen mehr per Funktionsaufruf, aber wenn sowas häufig passiert kann sich das sammeln und bei zeitkritischen oder intensiven Rechnungen ist das vielleicht nicht wünschenswert.

Dennoch benutze ich gelegentlich aber selten Variante 2 (oder sowas Ähnliches) wenn die Struktur ebenso ein Interface ist, also ein selbstgebautes "Objekt"; siehe unten im Beispiel bei der foo() Methode Zeile 22. Manchmal geht es auch nur mit Variante 2, wenn gerade verschiedene Strukturen und Datentypen übergeben werden können z.B. bei Konvertierungen wie bei PeekS() etc.

Code: Alles auswählen

; My Object
;
Structure MyObj
  *VT
  ; ....
EndStructure
;
; My Object Interface
Interface IMyObj
  free()
  foo()
  bar()
EndInterface
 ;
Procedure NewMyObj() ; Konstruktor
  Protected *New.MyObj = AllocateMemory(SizeOf(MyObj))
  *New\VT = ?VT_MyObj ; VT Zeiger setzen
  ProcedureReturn *New
EndProcedure
 ; Interface Methods
Procedure.i MO_foo(*Obj.MyObj) ; Methode foo
  Protected self.iMyObj = *Obj ;  Variante 2
  Debug "FOO"
  self\bar() ; foo() ruft das bar() des selbigen Objektes auf
EndProcedure
;
Procedure.i MO_bar(*Obj.MyObj) ; Methode bar
  Protected self.iMyObj = *Obj
  Debug "BAR"
EndProcedure
;
Procedure.i MO_free(*Obj.MyObj) ; interface method free
  *OBJ\VT = #Null
  Debug "FREE " + *Obj
  FreeMemory(*Obj)
  ProcedureReturn
EndProcedure

 ;
DataSection
  VT_MyObj: ; Interface Virtual Table (VT)
  Data.i @MO_free()
  Data.i @MO_foo()
  Data.i @MO_bar()
EndDataSection


This.IMyObj = NewMyObj()
This\foo()
this\free()

Re: Übergabe Structure an Procedure, was ist besser

Verfasst: 18.06.2023 00:01
von TroaX
Finde beide Varianten blöd. Bei Variante 1 würde ich erwarten, das mir der Compiler bzw. der Debugger in den Schoß speit, wenn ich ihm eine beliebige Adresse bzw. irgendein Pointer geben würde. Macht er dummerweise aber nicht, da er aus der Adresse nicht direkt ableiten kann, das es sich eben um keinen Pointer einer Struktur handelt. Ein Pointer passt in einen Int. Somit ist es völlig Egal, ob man *blahblah.Whatever oder nur *blahblah nutzt. Der Fehler wird erst in der ersten Zeile der Prozedur geschmissen. Er erkennt erst dann, das die Prozedur eine Struktur sein sollte, aber keine übergeben wurde. Noch bescheidener ist es, wenn man ihm den Pointer irgendeines numerischen Datentyps übergibt. Da schmeißt er keinen Fehler, obwohl er keinen Pointer einer Struktur bekommen hat. Am Ende ist ein Pointer immer ein "Int", weil eine Adresse nun einmal ein ganzzahliger Typ ist und da sehe ich leider einiges an Fehlerpotenzial. Da hilft meiner Meinung nach Variante 1 auch nicht. Das kann zwar wenigstens etwas helfen, wenn der Code schon geschrieben wurde. Hilft aber kaum, wenn man ihn noch schreiben muss. Eine aussagekräftige Fehlermeldung alá "Du Vogel gibst mir die Adresse eines Floats. Brauch aber Pointer des Typs -Whatever-" hingegen schon.

Wenn dieses Verhalten etwas strikter wäre und Strukturen als Übergabeparameter sowie auch als Rückgabe nativ unterstützt werden würden, dann würde sich denke ich mal die Frage garnicht stellen. Dann geht Variante 2 ohne Zeile 1 der Prozedur deutlich geschmeidiger von der Hand und wenn man es dann mit dem Parameter vergeigt, springt einem der Debugger ins Gesicht.

Re: Übergabe Structure an Procedure, was ist besser

Verfasst: 18.06.2023 00:33
von mk-soft
Ich bin für Variante 1 mit Angabe der Structure. Aber ohne Prüfung von den Debugger wie von TroaX angedeutet.
Sonst funktioniert Überlagerung von Strukturen nicht mehr wie ich bei Vererbung von Strukturen und Interfaces verwende.

Re: Übergabe Structure an Procedure, was ist besser

Verfasst: 24.06.2023 22:16
von juergenkulow

Code: Alles auswählen

; Structure Whatever Win x64 C Backend optimiert x64dbg zeigt:
; 0000000140001047        | 90              | nop                                    |
; 0000000140001048        | 48:8B05 7110000 | mov rax,qword ptr ds:[1400020C0]       |
; 000000014000104F        | 48:8905 9234000 | mov qword ptr ds:[1400044E8],rax       |
; 0000000140001056        | C705 90340000 0 | mov dword ptr ds:[1400044F0],C         | C:'\f'
; 0000000140001060        | 90              | nop                                    |
; 0000000140001061        | 48:8B05 6010000 | mov rax,qword ptr ds:[1400020C8]       |
; 0000000140001068        | 48:8905 8934000 | mov qword ptr ds:[1400044F8],rax       |
; 000000014000106F        | C705 87340000 0 | mov dword ptr ds:[140004500],2         |
; 0000000140001079        | 90              | nop                                    |
; 000000014000107A        | 4C:6305 7734000 | movsxd r8,dword ptr ds:[1400044F8]     |
; 0000000140001081        | 48:630D 7434000 | movsxd rcx,dword ptr ds:[1400044FC]    |
; 0000000140001088        | 48:6315 7134000 | movsxd rdx,dword ptr ds:[140004500]    | rdx:EntryPoint
; 000000014000108F        | 48:6305 5234000 | movsxd rax,dword ptr ds:[1400044E8]    |
; 0000000140001096        | 4C:630D 4F34000 | movsxd r9,dword ptr ds:[1400044EC]     | r9:EntryPoint
; 000000014000109D        | 4C:01C8         | add rax,r9                             | r9:EntryPoint
; 00000001400010A0        | 4C:630D 4934000 | movsxd r9,dword ptr ds:[1400044F0]     | r9:EntryPoint
; 00000001400010A7        | 4C:01C8         | add rax,r9                             | r9:EntryPoint
; 00000001400010AA        | 4C:01C0         | add rax,r8                             |
; 00000001400010AD        | 48:01C8         | add rax,rcx                            |
; 00000001400010B0        | 48:01D0         | add rax,rdx                            | rdx:EntryPoint
; 00000001400010B3        | 48:8905 4E34000 | mov qword ptr ds:[140004508],rax       |
  Structure Whatever
    a.l
    b.l[2]          ; Statisches Array (Standard C) mit 2 Werten b[0] und b[1], nicht in der Größe veränderbar
    
  EndStructure

  MyVar.Whatever
    MyVar2.Whatever

  Procedure MyProcedure2(blahblah)     
    *blahblah.Whatever = blahblah     
    *blahblah\a = 15
    *blahblah\b[0] = 11
    *blahblah\b[1] = 12
  EndProcedure
  Procedure MyProcedure(*blahblah.Whatever)
    *blahblah\a = 5
    *blahblah\b[0] = 1
    *blahblah\b[1] = 2
  EndProcedure
  ! asm("nop");
  MyProcedure2(MyVar2) 
  ! asm("nop"); 
  MyProcedure(@MyVar)  ;oder MyProcedure(MyVar) @ wird nicht benötigt
 ! asm("nop");
  l=MyVar2\a + MyVar2\b[0] + MyVar2\b[1] + MyVar\a + MyVar\b[0] + MyVar\b[1]
  SetClipboardText(Str(l)) ;46