Funktion Return verschiedene Datentypen?

Hallo Leute, ich habe nichts zu diesem Thema gefunden: Ist es möglich, eine Funktion so zu legen, dass sie Daten unterschiedlichen Typs zurückgibt? Da die Funktionsdefinition mit

'Variablentyp' 'Name' (Übergabeparameter) {...

anfängt, erscheint mir das zwar zweifelhaft aber vielleicht kennt jemand eine Möglichkeit, einen String und ein byte als result zu erhalten.

Du könntest void Zeiger zurückgeben... Aber schön ist das nicht...

Nicht über den Rückgabe-Wert, aber mit Zeigern als Parameter geht es:

void func(byte* b, char* str)
{
   *b = 5;
   strcpy(str, "test");
}

void setup()
{
   byte b;
   char str[10];

   func(&b, str);
}

Bei str muss man muss man nicht die Adressse mit & übergeben da Arrays automatisch in Zeiger zerfallen

Das gibt halt immer beides zurück. Nicht entweder oder.

Hm… Mal sehen, ob ich das hinkriege.
Danke erstmal! :slight_smile:

Die Fragestellung führt bei mir zu der Frage, warum du überhaupt den Bedarf hast unterschiedliche Datentypen zurückzubekommen. Du musst ja hinterher irgendwoher wissen, was für ein Datentyp zurückkam, um damit wieder was anfangen zu können.

Also klär uns doch bitte mal auf. Brauchst du genau ein Ergebnis und dieses könnte vom Typ X oder vom Typ Y sein (so verstehe ich es) oder brauchst du zwei Ergebnisse zugleich, die beide einen unterschiedlichen Typ haben?

Im letzteren Fall kannst du nämlich auch einfach den Datentyp struct nutzen und dir somit ein Objekt zurückgeben, das beide Werte enthält. In ersterem Fall würde ich gerne mal erfahren, was denn genau dein Anwendungsfall ist. Denn dann vermute ich, dass du zwei unterschiedliche Funktionalitäten in die selbe Funktion stopfen willst und eigentlich zwei Funktionen haben solltes.

Der erste Fall ist in der Tat ein Design-Fehler

TelosNox: Im letzteren Fall kannst du nämlich auch einfach den Datentyp struct nutzen und dir somit ein Objekt zurückgeben, das beide Werte enthält.

Das geht sogar Ressourcen-schonend dank Return Value Optimization: https://en.wikipedia.org/wiki/Return_value_optimization Was ein Speziall-Fall von Copy Elision ist: https://en.wikipedia.org/wiki/Copy_elision

Es werden also keine unnötigen Kopien erstellt. Das Beispiel auf der ersten Seite geht auch auf dem Arduino wenn man es entsprechend anpasst. Die Alternative sieht man wenn man spaßeshalber in platform.txt den -fno-elide-constructors Schalter hinzufügt. Das deaktiviert diese Optimierung. Und schon wird der Copy-Konstruktor zweimal aufgerufen (Extrapunkt wenn du beide Stellen findest).

In C/C++ (oder auch C#) halte ich das aber auch für etwas unsauber. Diese Konstruktion ist in Java nötig, da Java keine echten Referenzen hat (statt dessen werden Referenzen auf Objekte per Value übergeben). In einer Sprache mit richtigen Referenzen oder sogar Zeigern ist das unnötig.

Danke Euch allen! Das war ein guter Tipp von TelosNox. Ich wollte die berechnete Checksumme des NMEA-Strings und den String separat übergeben. Aber das geht ja viel einfacher: Man kann die berechnete und die gegebene Checksume ja sofort vergleichen und das Ergebnis erst dann übergeben, wenn beides übereinstimmt. Hier das (funktionierende) Ergebnis:

/*  Info: This scetch is tested on Arduino Nano V3.0 + Adafruit ultimate GPS breakout V.3
 *  Pin connections:
 *  Arduino Pin "5V"  -> GPS-Breakout Pin "VIN"
 *  Arduino PIN "GND" -> GPS-Breakout Pin "GND"
 *  Arduino PIN "D2"  -> GPS-Breakout Pin "RX"
 *  Arduino PIN "D3"  -> GPS-Breakout Pin "TX"
 *  Auf dem Adruino Nano V3.0 gibt es zwei "GND"-Pins - man kann jeden nehmen.

    *** Special thanks to Doc_Arduino, Serenifly & TelosNox @ forum.arduino.cc ***/

// *** GPS section ***
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(3,2);
#define PMTK_SET_NMEA_UPDATE_1HZ  "$PMTK220,1000*1F"
#define PMTK_SET_NMEA_OUTPUT_RMC "$PMTK314,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0*29"

void setup() {
// *** GPS section ***
  while (!Serial); // Prüfen, ob diese Zeile gelöscht werden kann.
  Serial.begin(9600);
  mySerial.begin(9600);
  delay(2000);
  mySerial.println(PMTK_SET_NMEA_OUTPUT_RMC);
  mySerial.println(PMTK_SET_NMEA_UPDATE_1HZ);
}

void loop() {
// *** GPS section ***
  //nmeaString = getNMEAString();
  Serial.println(getNMEAString());
}

// *** function section ***

// function to read a NMEA-String from GPS device
// return is the NMEA string or a String contains "error"
String getNMEAString() {
  String _NMEAString = "$";
  char _Zeichen;
  byte _CheckSumCalculated = 0;
  boolean _TransferSwitch = true;
  boolean _CheckSumCalculatorSwitch = false;
  boolean _StartRecord = false;
  unsigned int _NMEAStringLaenge;
  while (_TransferSwitch) {
    if (mySerial.available()) {
      _Zeichen = mySerial.read();
      if (_Zeichen == '

Edit: Hab noch den nicht dazu gehörenden RTC-Teil rausgenommen…
Ach ja: Ich hab da in eine Zeile “Prüfen ob diese gelöscht werden kann” reingeschrieben. Ist die wirklich notwendig? Das ist nämlich ein vorhandener Code gewesen, die ich bloß angepasst habe. Ich habe nur die Bedeutung dieser Zeile nicht verstanden.) {
        _StartRecord = ! _StartRecord;
        _CheckSumCalculatorSwitch = true;
        if (! _StartRecord) {
          _TransferSwitch = false;
        }
      } else {
        if (_StartRecord) {
          _NMEAString = _NMEAString + _Zeichen;
        }
        if (_Zeichen == ‘*’) {
          _CheckSumCalculatorSwitch = false;
        }
        if (_CheckSumCalculatorSwitch) {
          _CheckSumCalculated = _CheckSumCalculated ^ _Zeichen; // XOR-Checksumme bilden
        }
      }
    }
  }
// NMEA-String qualifizieren und bei positiver Bewertung übergeben
  _NMEAStringLaenge = _NMEAString.length();
  if (_NMEAString.substring(_NMEAStringLaenge - 4,_NMEAStringLaenge - 2).toInt() == String(_CheckSumCalculated,HEX).toInt()) {
    return _NMEAString;
  } else {
    return “error”;
  }
}


Edit: Hab noch den nicht dazu gehörenden RTC-Teil rausgenommen...
Ach ja: Ich hab da in eine Zeile "Prüfen ob diese gelöscht werden kann" reingeschrieben. Ist die wirklich notwendig? Das ist nämlich ein vorhandener Code gewesen, die ich bloß angepasst habe. Ich habe nur die Bedeutung dieser Zeile nicht verstanden.

Was deine kommentierte Zeile angeht: https://www.arduino.cc/en/Serial/IfSerial

Es sorgt dafür, dass dein Arduino so lange mit dem Setup wartet, bis etwas am Serial angeschlossen ist.

Wenn du sicherstellst, dass er nur dann hochfährt, wenn auch was dranhängt, dann kannst du das auch rausmachen. Es schadet so aber nicht.

Bist du sicher? Ich dachte, die steht aus Gründen der Kompatibilität mit alter HW (Leonardo?) noch oft in Sketchen. Neuere Arduino gehen auch ohne diese Zeile

Da könnte was dran sein. In einem der Quelltexte, die ich als Grundlage genommen habe, stand was von Leonardo und einem weiteren älteren Modell (vielleicht ne alte Unoversion) drin.

Leonardo ist kein älteres Modell, sondern eine relativ junge und schon wieder tote Abart, für den extra der bool Operator für Serial dazu erfunden wurde.
Ein “richtiger” Arduino wie der Uno merkt nicht, ob irgend was an Serial angeschlossen ist. und liefert immer true zurück. Wenn man nicht für den Leonardo programmiert, kann man sich das while (!Serial) {} schenken.

Arduino.CC stellt keine Leonardo mehr her, aber den MICRO, der kompatibel mit dem Leonardo ist (gleicher Controller)
Arduino.ORG stellt weiterhin Leonardo her.

Grüße Uwe