Pages: [1]   Go Down
Author Topic: Unterprogramm: Übergabe und Rückgabeparameter  (Read 3474 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
mal wieder eine Anfängerfrage:
Ich möchte einem Unterprogramm einen String übergeben und 2 Integerwerte zurückbekommen.
Das Unterprogramm soll aus dem String die beiden Werte extrahieren und als INT zurückgeben.
Kann ich da alle 3 Übergabevariablen in die Deklaration reinschreiben?
Also so:
Code:
void chkstring ( String readstring, int ret_val1, int ret_val2){
ret_val1 = irgendwas (readstring);
ret_val2 = was anderes (readstring);
}
(Das irgendwas/was anderes ist nur Platzhalter für meine Funktionen.
Ich frage deshalb, weil es nicht klappt. Mag jetzt sein, daß mein Code in der Sub noch buggy ist.
Ich würde nur gerne wissen, ob ich auf der richtigen "Spur" bin.

gruß/hk007
« Last Edit: October 23, 2012, 03:09:12 pm by uwefed » Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nein, so funktioniert es nicht.
Der Grund hat einen Namen: "Call bei Value".
Beim Aufruf Deiner Funktion werden nicht die Variablen selbst, sondern deren aktuelle Werte zu Zeitpunkt des Aufrufs übergeben. Damit änderst Du zwar innerhalb Deiner Funktion die Werte aber nicht die Variablen selbst.

Schau mal hier rein: http://arduino.cc/forum/index.php/topic,128651.0.html
Da hab ich witzigerweise genau Dein Problem beschrieben und als Beispiel gelöst :-)
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

Muss mal vorab erklären, daß ich aus der SPS-Welt komme, und da kann man Funktionen mit IN/IN-OUT/OUT Variablen definieren.
Ok. Hab das jetzt so verstanden, daß ich eine OUT-Variable nur dann beschreiben kann, wenn ich beim Aufruf den Pointer verwende.
Das würde dann für mein Beispiel so aussehen???
Code:
void chkstring ( String readstring, int *ret_val1, int *ret_val2){
*ret_val1 = irgendwas (readstring);
*ret_val2 = was anderes (readstring);
}

Nur noch eins:
Kann ich das Unterprogramm dann auch mehrmals mit verschiedener "Beschaltung" aufrufen?
Also so:
Code:
chkstring(stringin1, intval1a, intval1b):
chkstring(stringin2, intval2a, intval2b);
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 251
Posts: 21252
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Kann ich das Unterprogramm dann auch mehrmals mit verschiedener "Beschaltung" aufrufen?
ja natürlich.
Das machst Du ja dauernd zb mit digitalRead() ecc.

Nur würd ich das nicht Unterprogramm sondern Funktion nennen und die "Beschaltung" Übergabeparameter.

Die Funktionen, die Arduino kennt, sind nicht anders als eine Funktion die Du im Sketch selbst definierst und dann benutzt. Die anderen Funktionen sind in den verschiedenen Bibliothen definiert die automatisch includiert werden oder die Du includierst.

Grüße Uwe
 
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nur würd ich das nicht Unterprogramm sondern Funktion nennen und die "Beschaltung" Übergabeparameter.

OK,  smiley-grin

ich war mir nur nicht sicher, ob er dann auch immer die Werte die in der Funktion mit "*ret_val1" berechnet auch dem von aussen zugewiesenen Übergabeparametern "intval1a" etc. zuweist.
Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Also ich würde für sowas noch KEINE Pointer nehmen sondern Referenzen.

Beispiel mit Pointern:

Code:
void move_a_to_b(int a, int *b) {
    *b = a;
}

loop()  {
    int b;
    move_a_to_b(1, &b);
}

Und jetzt (besser) mit Referenzen:

Code:
void move_a_to_b(int a, int &b) {
    b = a;
}

loop()  {
    int b;
    move_a_to_b(1, b);
}

Mit Referenzen hat man nicht den ganzen Code unnötig mit "*" vollgepflastert.
« Last Edit: October 23, 2012, 03:58:56 pm by Udo Klein » Logged

Check out my experiments http://blog.blinkenlight.net

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Pointer <-> Referenz

jetzt wird es mir zu hoch.......
Vor allem, weil du in der Funktion das b benutzt und aussen auch noch mal.

Zum Unterschied Pointer <-> Referenzen ...Da muss ich mich wohl mal etwas einlesen...
« Last Edit: October 23, 2012, 04:11:23 pm by hk007 » Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Forum Moderator
BZ (I)
Offline Offline
Brattain Member
*****
Karma: 251
Posts: 21252
+39 349 2158303
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das übersteigt meinen Horizot.
Uwe
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

ich hab jetzt mal versucht das Ganze umzusetzen
Noch mal zu meiner Aufgabenstellung: ich bekomme über Ethernet einen String, in dem eine Uhrzeit enthalten ist. Die liegt irgendwo im String und sieht z.B. so aus:
Code:
23%3A59
Also 23:59 das %3A stellt den Doppelpunkt dar.
Jetzt will ich zwei Integer Variablen, in denen die Stunden und die Minuten enthalten sind.
Ich wollte eine Funktion dafür, da die Abfrage einige Male vorkommt, der String immer ähnlich aufgebaut ist, aber die Resultate in verschiedene Variablen geschrieben werden sollen.
Mein aktuelles Programm sieht so aus:
Code:
void chkstring ( String instring, int *ret_hour, int *ret_minute) {
             String substring =  (instring.substring(instring.indexOf("%3A")-2,instring.indexOf("%3A")));  
             char valueArray[substring.length() +1];              
             substring.toCharArray(valueArray, sizeof(valueArray));
             *ret_hour = atoi(valueArray);          
          
             String substring2 = (instring.substring(instring.indexOf("%3A")+3,instring.indexOf("%3A")+5));          
             char valueArray2[substring2.length() +1];              
             substring2.toCharArray(valueArray2, sizeof(valueArray2));
             *ret_minute = atoi(valueArray2);
}
void loop() {
             int hour1, hour2, minute1, minute2;
             chkstring(readString1, &hour1, &minute1);
             chkstring(readString2, &hour2, &minute2);
}

Kompilieren klappt, aber die Werte sind immer "0".

Wahrscheinlich hab ich das Ganze eh wieder zu kompliziert aufgebaut, oder???
« Last Edit: October 23, 2012, 04:47:06 pm by hk007 » Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

Offline Offline
Edison Member
*
Karma: 21
Posts: 1419
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das übersteigt meinen Horizot.
Referenzen sind kein Hexenwerk, aber wer viel C gemacht hat, wird durch diese C++ Erweiterung erstmal verwirrt, das ging mit auch so. Daher hab ich das bewußt erstmal nicht als Lösung angeboten :-)
Udo hat aber recht, es ist deutlich eleganter.

Im Prinzip wird aus dem üblichen "Call by Value", bei dem immer die Werte der Parameter auf den Stack gepackt werden wenn eine Funktion aufgerufen wird (default) ein "Call by reference" gemacht. Der Compiler sorgt also dafür das automatisch die Zeiger der Variablen an die Funktion übergeben werden (quasi eine Referenz auf die Werte). Man spart sich dadurch das "verpointern" bei der Übergabe und das ständige dereferenzieren der Pointer beim Rechnen. Das macht den Code übersichtlicher und weniger fehleranfällig. Wenn man statt "*a++" nämlich nur "a++" schreibt, das "a" aber ein Pointer ist, wird der Compiler nicht meckern, trotzdem kommt Murks raus :-)

Code:

void pointer_swap( int* a, int* b) {
 int temp = *b;
 *b = *a;
 *a = temp;
}

int referenz_swap( int &a, int &b) {
 int temp = b;
 b = a;
 a = temp;

}

void setup() {
 Serial.begin(9600);
 
 int a = 1;
 int b = 2;

 Serial.print(a);
 Serial.print(" - ");
 Serial.println(b);
 

 pointer_swap(&a,&b);

 Serial.print(a);
 Serial.print(" - ");
 Serial.println(b);

 referenz_swap(a,b);

 Serial.print(a);
 Serial.print(" - ");
 Serial.println(b);

}

void loop() {
  // put your main code here, to run repeatedly:
 
}

Beider Funktionen machen das Gleiche, nur ist die Verwendung von referenz_swap() deutlich übersichtlicher weil man a und b direkt verwenden kann.
Logged

Offline Offline
Sr. Member
****
Karma: 1
Posts: 353
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,

jetzt hab ichs kapiert. Und läuft auch bei mir.
Danke für die geduldigen Erklärungen.

Ich stell mal meinen Code rein, falls es mal jemand brauchen kann.
Das Extrahieren der Integer hab ich auch etwas einfacher gestaltet.
Ich hoffe der charAt() ist ok, den hab ich vorhin irgendwo aufgeschnappt. Aber so spar ich mir das wandeln ich ein charArray.
Code:
void chkstring ( String instring, int &ret_hour, int &ret_minute) {
             int DP = (instring.indexOf("%3A"));   //Doppelpunkt suchen
             ret_hour = ((int(instring.charAt(DP-2))-48)*10) + (int(instring.charAt(DP-1))-48); // die 2 Zeichen vor dem Doppelpunkt in Zahl wandeln
             ret_minute = ((int(instring.charAt(DP+3))-48)*10) + (int(instring.charAt(DP+4))-48); // die 2 Zeichen nach dem Doppelpunkt in Zahl wandeln           
}
//Aufruf:
           chkstring (readString, hour, minute);

Logged

Arduino 1.0.5 | Arduino UNO & MEGA | Arduino 1.54r2 mit DUE

0
Offline Offline
Faraday Member
**
Karma: 23
Posts: 3470
20 LEDs are enough
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Vor allem, weil du in der Funktion das b benutzt und aussen auch noch mal.

Das nennt man "verschatten" von Variablen. Die Funktion hat einen lokalen Namensraum der den globalen Namensraum überdeckt. D.h. das b in der Funktion ist der Name des Parameters, das b außen ist der Name der Variablen. Aus Sicht des Compilers hätte ich auch

Code:
void move_a_to_b(int c, int &d) {
    d = c;
}

loop()  {
    int b;
    move_a_to_b(1, b);
}

schreiben können. Und wenn wir schon dabei sind, gefühlt sauberer wäre natürlich

Code:
void move_a_to_b(const int a, int &b) {
    b = a;
}

loop()  {
    int b;
    move_a_to_b(1, b);
}

obwohl das aus Sicht des Compilers in diesem Fall keinen großen Unterschied macht. Man könnte fast sagen, eigentlich gar keinen.
Logged

Check out my experiments http://blog.blinkenlight.net

Pages: [1]   Go Up
Jump to: