PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Das Funktionen-Byref/Byval-Variablenchaos - Verständnisfragen



Thomas E.
07.10.2012, 15:04
Hallo!


Nach langer Zeit habe ich mich gestern das erste Mal über Subroutinen und Funktionen getraut. Bisher schrieb ich teilweise sehr umfangreiche Programme lediglich mit jede Menge Routinen, die per Gosub angesprochen wurden. Es funktionierte zwar, war aber manchmal zu langsam und zu unübersichtlich.

Nach genauem Studium der Literatur (Internet, Bücher und Bascom-Hilfe) über Prozeduren und Funktionen hat mich teilweise über deren Wirkungsweise aufgeklärt, aber dennoch tauchen einige unbeantwortete Fragen auf. Auch möchte ich wissen, ob ich es denn richtig verstanden habe.

Mein Wissensstand:

Eine Prozedur (Declare Sub) kann mit übergebenen Variablen arbeiten
Eine Funktion (Declare Function) kann mit übergebenen Variablen arbeiten und liefert einen Wert zurück
Innerhalb einer Prozedur oder Funktion kann ich mittels LOCAL Prozedur-/Funktionseigene Variablen definieren, die außerhalb der Prozedur nicht sichtbar sind
Übergebe ich eine Variable mit Byref wird lediglich die Adresse der zu übergebenen Variable weitergegeben
Übergebe ich eine Variable mit Byval wird die Variable kopiert


Ein Beispielcode:


'GLOBAL
Dim a as Byte
Dim b as Byte
Dim c as Byte

Declare Function myfunction (a as Byte, b as Byte) as Byte

Do
c = myfunction(a,b)
Loop

Function myfunction (a as Byte, b as Byte)
myfunction = a + b
End Function

End

Ich habe jetzt drei globale Variablen definiert (a, b und c). Anschließend deklariere ich die Funktion myfunction mit zwei Übergabevariablen, die pfiffigerweise ebenfalls wie die globalen Variablen a und b heißen. Diese werden allerdings nicht kopiert, sondern nur die Adresse wird an die Funktion weitergegeben.
In der Hauptschleife rufe ich die Funktion auf, in dem ich ein Ergebnis für die globale Variable c verlange. Dabei werden die globalen Variablen a und b an die Übergabevariablen a und b (ich find das extrem gemein) übergeben. Anschließend wird in der Funktion das Zeug zusammengerechnet und das Ergebnis wieder in die Hauptschleife in die globale Variable c kopiert. Fertig!

Laut Simulator läuft die Sache so.

So, nun zu den Fragen, die mich interessieren:
Ist es wirklich kein Problem, globale Variablen gleich zu bennen wie Übergabevariablen (außer Verwirrung)?
Welche Nachteile ergeben sich durch die Verwendung von byref, beziehungsweise wann kann die Variable fälschlicherweise geändert werden?
Hat jemand Beispiele von richtig eingebundenen Funktionen/Prozeduren aus der Praxis oder in einem bestehendem Projekt?

Warscheinlich sind die Antworten eh ganz einfach und logisch aber ich scheine gerade voll auf dem Schlauch zu stehen. ;)

Danke für eure Hilfe.

Thomas E.
07.10.2012, 15:53
Die Verwendung von Byval/Byref habe ich gerade durch Ausprobieren verstanden:


Dim X as Byte
Dim Ergebnis as Byte

Declare Function abc (a as Byte) as Byte

Do

Ergebnis = abc(x)

Loop

Function abc (a as Byte)

Shift a , left , 2
abc = a

End Function

End

Diese Variante verändert beim zweimaligen Schieben der übergebenen Variable a ebenfalls die globale (Ursprungs-) Variable x, da ja die Variable gar nicht "real" an die Funktion übergeben wurde, sondern nur die Adresse der Variable x. Das ist warscheinlich schnell und speichersparend, aber in diesem Fall doof und unerwünscht.

Mit der Verwendung von byval wird x einfach kopiert und dieser Klon wird dann in der Funktion geschoben und wieder zurückkopiert.

Dazu noch eine Frage: Wird der Speicher nach verlassen der Funktion wieder freigegeben?

Schön langsam wirds ja... ;)

for_ro
07.10.2012, 16:12
Hallo Thomas,
dein Wissensstand ist vollkommen in Ordnung.
Eine Sache hierzu: Es funktionierte zwar, war aber manchmal zu langsam und zu unübersichtlich.
Durch die Verwendung von Subs oder Funktionen wird es nicht schneller, im Gegenteil, du bekommst etwas Overhead.
Übersichtlicher wird es auf jeden Fall und daher ist die Verwendung sicherlich richtig.

Ich würde grundsätzlich vermeiden, für eine lokale Variable den gleichen Namen zu verwenden, wie für eine globale.
Ein Fehler von MCS beim Programmieren des Compilers und schon wird der falsche Wert verwendet. Ich meine mich sogar zu erinnern, dass es das auch schon einmal gegeben hat im Zusammenhang mit gleichen Namen.


Den "Nachteil" von ByRef hast du ja schon gesehen. Wenn man darum weiß, ist es allerdings eher ein Vorteil.
Arrays kannst du übrigens gar nicht anders übergeben, da bei ihnen nur die Startadresse übergeben und nichts kopiert wird.
Strings werden mit ByVal kopiert, aber du kannst dir vorstellen, dass dabei einiges an Zeit draufgeht -> Overhead.
Es wird übrigens nichts "zurückkopiert".

Hast du dir die Beispiele in den Samples schon angesehen, dort ist einiges erklärt.

Der Speicher wird beim Verlassen der Funktion wieder freigegeben.
Zu beachten ist noch, dass die lokalen Variablen nicht mit 0 oder "" vorbelegt werden. Sie enthalten einfach das, was beim letzten Verwenden der Speicherzelle dort stand.

Thomas E.
07.10.2012, 16:27
Hallo Thomas,
dein Wissensstand ist vollkommen in Ordnung.
Eine Sache hierzu: Es funktionierte zwar, war aber manchmal zu langsam und zu unübersichtlich.
Durch die Verwendung von Subs oder Funktionen wird es nicht schneller, im Gegenteil, du bekommst etwas Overhead.
Übersichtlicher wird es auf jeden Fall und daher ist die Verwendung sicherlich richtig.

Mit langsam habe ich mich etwas unglücklich ausgedrückt: Ich meinte das Schreiben des Programms an sich, nicht die Ausführgeschwindigkeit. Sry. :)


Ich würde grundsätzlich vermeiden, für eine lokale Variable den gleichen Namen zu verwenden, wie für eine globale.
Ein Fehler von MCS beim Programmieren des Compilers und schon wird der falsche Wert verwendet. Ich meine mich sogar zu erinnern, dass es das auch schon einmal gegeben hat im Zusammenhang mit gleichen Namen.

Also geht es, ist aber furchtbar böse und unübersichtlich - das habe ich mir fast schon gedacht.
Wie verhält es sich mit zwei einzelnen Funktionen, die beide als Übergabevariablen A und B haben? Da sie lokal sind, wäre das denkbar?


Den "Nachteil" von ByRef hast du ja schon gesehen. Wenn man darum weiß, ist es allerdings eher ein Vorteil.
Arrays kannst du übrigens gar nicht anders übergeben, da bei ihnen nur die Startadresse übergeben und nichts kopiert wird.
Strings werden mit ByVal kopiert, aber du kannst dir vorstellen, dass dabei einiges an Zeit draufgeht -> Overhead.
Es wird übrigens nichts "zurückkopiert".

Achso: Die lokale Variable wird dann ja sowieso entfernt da die Prozedur/Funktion verlassen wird.


Der Speicher wird beim Verlassen der Funktion wieder freigegeben.
Zu beachten ist noch, dass die lokalen Variablen nicht mit 0 oder "" vorbelegt werden. Sie enthalten einfach das, was beim letzten Verwenden der Speicherzelle dort stand.
Auch beim definieren einer lokalen Variable mit LOCAL?

Danke nochmals für die Hilfe! :)

MagicWSmoke
07.10.2012, 16:42
Ist es wirklich kein Problem, globale Variablen gleich zu bennen wie Übergabevariablen (außer Verwirrung)?
Kommt auf die Bascom-Version an, siehe history.txt:

2.0.5.0
- local variables may now have the same name as global variables.

Auch beim definieren einer lokalen Variable mit LOCAL?
Eigentlich nur da, denn die einzig andere/n lokale/n Variable/n, also übergebene Funktionsparameter, haben einen Wert. Nämlich den sie beim Aufruf der Funktion übergeben bekamen.


Ein Fehler von MCS beim Programmieren des Compilers und schon wird der falsche Wert verwendet.
So'ne Aussage ist ja recht sinnfrei, denn wenn bei MCS ein Fehler im Compiler entsteht, dann geht u.U. gar nix mehr.
Von einem Fehler grundsätzlich und speziell bei die Namensgebung von Variablen auszugehen, stellt im Prinzip jegliche Programmierung in Frage und macht auch so keinen Sinn.
Abgesehen davon würde ich zustimmen, gleiche Namen für lokale und globale Variablen kann man locker vermeiden.