Pages: [1]   Go Down
Author Topic: 2 gleichnamige Funktionen in der Library  (Read 1135 times)
0 Members and 1 Guest are viewing this topic.
Meran/BZ/IT
Offline Offline
Full Member
***
Karma: 0
Posts: 184
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,
ich versuch mich gerade mit Pointern anzufreunden und studier deshalb grad eine Library für die RTC  DS1307.
Darin hab ich nun 2 gleichnamige Funktionen gefunden, wobei eine die andere aufzurufen scheint.
Code:
void DS1307::get(uint8_t *sec, uint8_t *min, uint8_t *hour, uint8_t *day, uint8_t *month, uint16_t *year)
{
  //get time and date
  Wire.beginTransmission(DS1307_ADDR);
  Wire.send(0x00);
  Wire.endTransmission();
  Wire.requestFrom(DS1307_ADDR, 7);
  *sec   = bcd2bin(Wire.receive() & 0x7F);
  *min   = bcd2bin(Wire.receive());
  *hour  = bcd2bin(Wire.receive());
           bcd2bin(Wire.receive()); //day of week
  *day   = bcd2bin(Wire.receive());
  *month = bcd2bin(Wire.receive());
  *year  = bcd2bin(Wire.receive()) + 2000;

  return;
}


void DS1307::get(int *sec, int *min, int *hour, int *day, int *month, int *year)
{
  return get((uint8_t*)sec, (uint8_t*)min, (uint8_t*)hour, (uint8_t*)day, (uint8_t*)month, (uint16_t*)year);
}

Was ist der Sinn und wie funktioniert dies????
Müßte nicht eine Funktion allein reichen?
Wieso wird in der zweiten Funktion bei
Code:
(uint8_t*)sec
die Klammer gesetzt?

Danke im Voraus für Eure Hilfe!
Reinhard
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Die zwei Funktionen haben zwar den gleichen Namen aber eine unterschiedliche Signatur, d.h. Anzahl und / oder Typen der Parameter sind verschieden. Dadurch kann der Compiler die auseinanderhalten, sind praktisch zwei verschiedene Funktionen.

Die Klammer-Schreibweise ist ein sog. Type-Casting, da wird ein Wert eines Typs in einen anderem umgewandelt (gecastet).
Die obere Funktion verlangt die Parameter im Typ uint8_t (irgend ein spezieller Typ der irgendwo definiert wurde, ich nehme mal un unsigned (vorzeichenlos) integer 8 bit), die untere Funktion hat die Werte aber im Typ int (genau genommen jeweils Zeiger auf ..).
Das passt erst mal nicht zusammen, muss also gecastet werden. Wobei theoretisch der Wertebereich beim int höher sein dürfte als beim uint8_t, das Casten also nicht ganz sauber ist, da aber als Werte bei Skunde, Minute etc. soweiso keine höheren Werte als 255 auftreten können passt das hier schon.
Logged

Neuss
Offline Offline
Full Member
***
Karma: 1
Posts: 200
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

ich versuch mich gerade mit Pointern anzufreunden...
Löblich, oder verwerflich (je nach persönlicher Einstellung). Man kann mit so einem Pointer irrtümlich ganz beliebig irgendwo hinschreiben smiley-wink
Quote
Darin hab ich nun 2 gleichnamige Funktionen gefunden, wobei eine die andere aufzurufen scheint.
Code:
void DS1307::get(uint8_t *sec, uint8_t *min, uint8_t *hour, uint8_t *day, uint8_t *month, uint16_t *year)
{
...
  return;
}


void DS1307::get(int *sec, int *min, int *hour, int *day, int *month, int *year)
{
  return get((uint8_t*)sec, (uint8_t*)min, (uint8_t*)hour, (uint8_t*)day, (uint8_t*)month, (uint16_t*)year);
}

Was ist der Sinn und wie funktioniert dies????
Das Stichwort lautet (Funktions-)Überladung. Dabei können mehrere Funktionen den gleichen Namen haben. Sie müssen sich nur im Typ und/oder der Anzahl der übergebenen Parameter unterscheiden (im Beispiel einmal Pointer auf 8-Bit-Werte und einmal Pointer auf 16-Bit-Werte).  Auf diese Weise kann der Ersteller der Library für seine Nutzer spezialisierte Versionen einer Funktion zur Verfügung stellen. Man stelle sich zum Beispiel eine Funktion mit Namen Multi() vor, die einmal zur Multiplikation von 8-Bit int-Werten oder zur Multiplikation von 16-Bit int-Werten oder zur Multiplikation von float-Werten dienen kann. Es gäbe dann drei Funktionen, die alle Multi heißen, sich aber im Typ der Parameter unterscheiden würden.
Quote
Müßte nicht eine Funktion allein reichen?
Kommt drauf an. Braucht man nur eine Version, dann ja. Möchte man unterschiedliche Versionen zur Verfügung stellen, dann nein.
Dann könnte man zwar auch komplett unterschiedliche Versionen schreiben, aber der Aufwand wäre natürlich größer. Hier in diesem Fall wird die 1. Version von get() praktisch "recycelt", um ohne großen Aufwand eine 2. Version zu schaffen.
Quote
Wieso wird in der zweiten Funktion bei
Code:
(uint8_t*)sec
die Klammer gesetzt?
Die zweite Funktion get() hat ja Pointer auf int-Werte als Parameter. Da in der 2. Funktion aber die ursprüngliche 1. Version mit Pointern auf 8-Bit-Werte aufgerufen wird, muss mit (uint8_t*) der Datentyp des Parameters auf uint8_t* gewandelt werden, damit "es passt". Diese Kontruktion nennt man "cast". Damit wird also der übergebene Datentyp "pointer auf int" bei der 2. Version von get() auf den Datentyp "pointer auf "uint8_t" gewandelt.
Quote
Danke im Voraus für Eure Hilfe!
Bitte, gern geschehen.
Wolfgang

Edit: Da war wohl jemand schneller. Aber ich war ausführlicher smiley-wink
« Last Edit: November 03, 2011, 04:56:58 am by voithian » Logged

Meran/BZ/IT
Offline Offline
Full Member
***
Karma: 0
Posts: 184
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Danke!

Das bringt mich auf dem Pfad der Erleuchtung schon ein gutes Stück weiter.
Besonders die Sache mit den verschiedenen Funktionen unter dem selben Namen!

Könnt Ihr Literatur über solche und andere Feinheiten der Arduino-Programmierung empfehlen ( Buch, aber auch Web-Tutorial)?

thx Reinhard
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Das ist ja eher nicht Arduino-typisch sondern ganz klassisch C. Der "normale" Arduino-Nutzer soll sich mit Pointern etc. ja gar nicht rumärgern müssen.
Logged

Neuss
Offline Offline
Full Member
***
Karma: 1
Posts: 200
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Könnt Ihr Literatur über solche und andere Feinheiten der Arduino-Programmierung empfehlen ( Buch, aber auch Web-Tutorial)?
Das hat ja (fast) nichts mit Arduino-Programmierung tun, sondern ist ja reines C++. Genauso wie deine Beschäftigung mit den Pointern.

Da gibt es eine ganze Reihe von Fachbüchern zu diesen Themen, aber ich würde einfach mal mit google auf die Suche nach c++ und tutorial gehen. Da dürfte sich sicherlich einiges finden lassen. Anschauen und zum Lernen verwenden, wenn es gefällt.
Logged

Meran/BZ/IT
Offline Offline
Full Member
***
Karma: 0
Posts: 184
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hallo,
angenommen ich habe nun 2 Funktionen.
   void func (int i) { }
   void func (byte i) { }
Die erste wird aufgerufen, wenn als Wert ein int-Wert, die zweite, wenn ein byte-Wert übertragen wird.
Wenn ich nun aber beim Funktionsaufruf einen fixen Wert direkt eintrage:
   void func ( 222 );
Wie kann ich nun sicher sein, welche der beiden Möglichkeiten verwendet wird?
   void  func ( int 222 );     ???????
oder:
   int a = 222;
   void func (a);
Die letzte Möglichkeit ist halt genau das, was ich nicht wollte, nämlich eine optische Verlängerung des Codes und weniger Übersicht.....
Da kann ich gleich 2 verschiedennamige Funktionen nehmen.

Danke im Voraus für Eure Hilfe
Reinhard
Logged

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

Welche Funktion aufgerufen wird hängt von den verwendeten Typen ab. Damit irgendetwas den gewüschten Typ bekommt verwendet man einen Typecast, also

Code:
f((int) a);
f((byte) a);

erzwingt, daß a einmal als int und einmal als byte übergeben wird und damit werden dann (falls vorhanden) die Funktionen mit der passenden Signatur angesprochen.
Logged

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 42
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich bin mir nicht ganz sicher aber in
Code:
func ( 222 );
sollte der Compiler die 222 als int interpretieren wenn man nicht explizit was anderes angibt.
Aber solche Mehrdeutigkeiten sollte man besser vermeiden, also wie schon geschrieben im Zweifel lieber explizit casten.
Logged

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

Wenn a eine Konstante ist (was ich nicht vorausgesetzt habe), dann kann man den Typ auch durch geeignete Suffixe erzwingen. Wenn man sich nicht sicher ist, dann sollte man nicht auf das Compilerverhalten hoffen. 2 Wochen später weiß man sonst nicht mehr was man sich eigentlich dabei gedacht hat --> dann lieber gleich explizit den Typ erzwingen.
Logged

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

Neuss
Offline Offline
Full Member
***
Karma: 1
Posts: 200
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wenn a eine Konstante ist (was ich nicht vorausgesetzt habe), dann kann man den Typ auch durch geeignete Suffixe erzwingen.
Ich hatte ja auch schon ähnliche Suffixe für Konstanten gesucht wie u oder l  (z.B. 222ul, um zu sagen dass es sich um eine Konstante vom Typ unsigned long handelt) aber ich habe nichts gefunden, um ausdrücklich zu sagen, dass es sich bei 222 um "stinknormale" int oder byte oder andere 8-bit Datentypen handelt.

Weiss jemand anders mehr als ich? smiley-wink

« Last Edit: November 13, 2011, 05:33:18 am by voithian » Logged

Neuss
Offline Offline
Full Member
***
Karma: 1
Posts: 200
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ich bin mir nicht ganz sicher aber in
Code:
func ( 222 );
sollte der Compiler die 222 als int interpretieren wenn man nicht explizit was anderes angibt.
Kannst dir aber sicher sein. Ausprobiert. Tut er. Es wird die int-Version von func() aufgerufen.
Quote
Aber solche Mehrdeutigkeiten sollte man besser vermeiden,...
Wohl wahr...
Quote
... also wie schon geschrieben im Zweifel lieber explizit casten.
Auch ausprobiert. Funktioniert wie erwartet.
Logged

Pages: [1]   Go Up
Jump to: