Übergabe Structure an Procedure, was ist besser

Für allgemeine Fragen zur Programmierung mit PureBasic.
Benutzeravatar
hjbremer
Beiträge: 822
Registriert: 27.02.2006 22:30
Computerausstattung: von gestern
Wohnort: Neumünster

Übergabe Structure an Procedure, was ist besser

Beitrag 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]

Purebasic 5.70 x86 5.72 X 64 - Windows 10

Der Computer hat dem menschlichen Gehirn gegenüber nur einen Vorteil: Er wird benutzt
grüße hjbremer
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Übergabe Structure an Procedure, was ist besser

Beitrag von NicTheQuick »

Das erste finde ich besser. Dann erkennt man direkt an der Prozedurdeklaration, dass sie einen Pointer mit der Struktur "Whatever" erwartet.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Übergabe Structure an Procedure, was ist besser

Beitrag 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.
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
Benubi
Beiträge: 187
Registriert: 22.10.2004 17:51
Wohnort: Berlin, Wedding

Re: Übergabe Structure an Procedure, was ist besser

Beitrag 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()
Benutzeravatar
TroaX
Beiträge: 684
Registriert: 08.03.2013 14:27
Computerausstattung: PC: Ryzen 9 3950X, 96 GB RAM, RX6800XT, 2.5 TB SSD, 21:9 Display, Linux Mint | Lappi: Ryzen 7 5800H, 16 GB RAM, 1 TB SSD, Linux Mint
Wohnort: NRW
Kontaktdaten:

Re: Übergabe Structure an Procedure, was ist besser

Beitrag 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.
PC: Ryzen 9 3950X | 96 GB RAM | RX6800XT | 2,5 TB NVMe | Linux Mint
Notebook: 16" 3:2 | Ryzen 7 5800H | 16 GB RAM | Radeon Vega | 1TB NVMe | Linux Mint
NAS: Fritz.Box 5690 Pro (Nur für Keepass-DB)
Coding: Purebasic, Spiderbasic, GDevelop, Javascript/Node
Benutzeravatar
mk-soft
Beiträge: 3855
Registriert: 24.11.2004 13:12
Wohnort: Germany

Re: Übergabe Structure an Procedure, was ist besser

Beitrag 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.
Alles ist möglich, fragt sich nur wie...
Projekte ThreadToGUI / EventDesigner V3 / OOP-BaseClass-Modul
Downloads auf MyWebspace / OneDrive
Benutzeravatar
juergenkulow
Beiträge: 188
Registriert: 22.12.2016 12:49
Wohnort: :D_üsseldorf-Wersten

Re: Übergabe Structure an Procedure, was ist besser

Beitrag 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 
Bitte stelle Deine Fragen, denn den Erkenntnisapparat einschalten entscheidet über das einzig bekannte Leben im Universum.

Jürgen Kulow Wersten :D_üsseldorf NRW D Europa Erde Sonnensystem Lokale_Flocke Lokale_Blase Orion-Arm
Milchstraße Lokale_Gruppe Virgo-Superhaufen Laniakea Sichtbares_Universum
Antworten