findet keine passende Signatur

Hallo,

ich baue mir gerade für die ATmegaAVR0 Reihe eine Usart Lib nach. Um nicht ständig mit putc, puts, ltoa und deren Verwandten im Code handieren zu müssen habe ich die Arduino print Methoden nachgebaut. Das funktioniert soweit bis auf die letzte Testzeile wo ich einen Floatwert 1.999 direkt übergebe. Hierfür findet der Compiler komischerweise keine passende print Signatur. Was mache ich falsch?
Fehlermeldung: “call of overloaded ‘print(double)’ is ambiguous”

Um Missverständisse vorzubeugen. Der Code läuft so nicht in der Arduino IDE. Ich mache das “zwangsweise” in Atmel Studio ohne Arduino Framework. Bei Bedarf/Notwendigkeit kann ich euch das Codepaket für AS7 geben.

Alle meine Print Methoden:

void print(const int8_t var)
{
  printInteger(var);
}

void print(const uint8_t var)
{
  printInteger(var);
}

void print(const int16_t var)
{
  printInteger(var);
}

void print(const uint16_t var)
{
  printInteger(var);
}

void print(const int32_t var)
{
  printInteger(var);
}

void print(const uint32_t var)
{
  printInteger(var);
}

void print(const float var)
{
  printFloat(var, 2);     // standardmäßig 2 Dezimalstellen
}

void print(const float var, const uint8_t digits)
{
  printFloat(var, digits);
}

void printFloat(float input, uint8_t digits)
{
  if (digits > 4) {       // limitiert auf 4 Dezimalstellen
    digits = 4;
  }

  double rounding = 0.005;

  switch (digits)
  {
    case 0:     rounding = 0.5;         break;
    case 1:     rounding = 0.05;        break;
    case 2:     rounding = 0.005;       break;
    case 3:     rounding = 0.0005;      break;
    case 4:     rounding = 0.00005;     break;
    default:    break;
  }

  input += rounding;

  int32_t vk = static_cast<int32_t> (input);
  printInteger(vk);
  putChar('.');

  double nk = input - (int32_t)vk;

  for (uint8_t i = 0; i < digits; ++i)
  {
    nk *= 10;
  }

  printInteger(static_cast<uint32_t>(nk));
}


template <class T>
void printInteger(const T var)
{
  char buffer[11];
  if (var < 0) {
    ltoa(var, buffer, 10);
  }
  else {
    ultoa(var, buffer, 10);
  }
  putString(buffer);
}

void print(const char *s)
{
  while (*s)
    putChar(*s++);
}

void println(const char *s)
{
  print(s);
  putChar('\n');
}

void println(void)
{
  putChar('\n');
}

Testausgaben:

usart1.println("Hallo ich bin USART1");

usart1.print("QWERTZ"); usart1.putChar('\n');
usart1.println("QWERTZ-ln");

char text[] = "ASDFG";
usart1.print(text); usart1.putChar('\n');
usart1.putString(text); usart1.putChar('\n');

uint8_t b = 125;
usart1.print(b); usart1.putChar('\n');

int16_t c = 1255;
usart1.print(c); usart1.putChar('\n');

int32_t d = -451255;
usart1.print(d); usart1.putChar('\n');

float f = 123.666666;
usart1.print(f);   usart1.putChar('\n');
usart1.print(f, 3); usart1.putChar('\n');
usart1.print(f, 4); usart1.putChar('\n');
usart1.print(f, 5); usart1.putChar('\n');
usart1.print(f, 6); usart1.putChar('\n');
usart1.print(1.999, 2); usart1.putChar('\n');
usart1.print(1.999); usart1.putChar('\n');  // findet keine print Signatur

habe ich die Arduino print Methoden nachgebaut

Man sollte für seine Hardware eine Klasse von Print [Nachtrag: oder besser gleich von Stream] ableiten und muss dann dort nur die virtuelle Methode
size_t write(byte);
hardwarespezifisch implementieren, und kriegt so die ganze print - Funktionalität geschenkt.

Er hat aber keine Arduino IDE hier

Statt eine extra Methode für die Nachkommastellen zu machen ist es einfach mit Default-Parametern zu arbeiten

Fehlermeldung: “call of overloaded ‘print(double)’ is ambiguous”

In der Regel nennt der Kompiler die möglichen Kandidaten.
Kann sein, dass dich das nicht interessiert.
Aber darin steckt ein/der Hinweis auf die Lösung.

Hallo,

@ Micha:
Von Arduino kann ich leider nichts verwenden. Ein paar Dinge habe ich mir abgeschaut. Hintergrund ist der das ich einen ATmega4809 komplett verwenden möchte. Das Arduino Nano Every Board hat leider nicht alle Pins rausgeführt. Vor mir liegt ein Microchip ATmega4809 Curiosity Nano Board. Das als Nebeninfo. Vielleicht kann man das später für eine Boarderweiterung für die Arduino IDE verwenden. Das weiß ich jetzt noch nicht. Ich muss erstmal so zurecht kommen.

@ Serenifly:
Wie meinst du das mit Default Nachkommastellen? Defaultmäßig gebe ich 2 Kommastellen aus wenn kein Parameter dafür übergeben wurde. Dafür sind die zwei print "float Signaturen" gedacht.

@ combie:
Die Einzigste Fehlermeldung die ich bekomme war die gezeigte Fehlermeldung: "call of overloaded 'print(double)' is ambiguous". Diese zeigt auf die Codezeile:

usart1.print(1.999); usart1.putChar('\n');  // findet keine print Signatur

Mehr Informationen gibt mir AS bzw. der Compiler nicht. Option -v ist aktiv.
Ich für meinen Teil sehe zwei saubere print Methoden für Datentyp float. Mit einem und zwei Parametern. Sollten saubere unterscheidbare Signaturen sein. Macht er mit der Testvariablen f anstandslos. Irgendwie kann er aus der Direktangabe 1.999 keinen float Datentyp erkennen, so scheint mir?

1.999 ist genaugenommen ein double, kein float. Falls das die Ambiguität ausmacht.
Probier mal, ob 1.999F ohne Fehler durchgeht.

Hallo,

Vielen Dank. Habe die Parameter der print float Signatur in double geändert und schon klappt es. :slight_smile:
Ist irgendwie sehr empfindlich was float vs. double angeht.

Ich dachte bis jetzt float und double sind beides float Datentypen nur das double genauer ist.

void print(const double var)
    {    
        printFloat(var, 2);     // standardmäßig 2 Dezimalstellen
    }        
        
    void print(const double var, const uint8_t digits)
    {              
        printFloat(var, digits);
    }

Die weitere Übergabe von double nach float stört ihn komischerweise nicht. Ändere ich dennoch auf double um.

void printFloat(float input, uint8_t digits)        
    {

Wenn jemand noch paar Hinweise hat nehme ich die gern auf.

https://en.cppreference.com/w/cpp/language/default_arguments
So macht es auch die Arduino Software

michael_x:
1.999 ist genaugenommen ein double, kein float.

Daran hatte ich auch schon gedacht

Hallo,

guter Tipp. Danke.

Hallo,

eine Frage bleibt noch offen. Warum ist 1.999 ein double und kein float?
Für mich wäre von der Genauigkeit her float eine Art "Teilmenge" von double.
1.999 kann float oder double sein in meinen Augen. Nur das double auf unseren µC gleich float ist.

Warum - Fragen sind traditionell schwierig. Ist eben so!

Guck hier bei Suffix: 1.0 ist double, 1.0F ist singleprecision float. Und dann gibt's noch L für einen long double.

Warum der Compiler so pingelig ist, wenn er ein float erwartet und du ihm ein double gibst, wäre die nächste warum-Frage. Und das bei Konstanten, die der Compiler leicht wandeln kann.
Und warum das umgekehrt ( signatur sagt double, er kriegt ein float ) egal ist. (Ist das so?)

traditionell schwierig

Historie:

Fließkomma Konstanten sind per default double.
Denn auf den meisten Systemen ist double das Format, auf dem die FP Units moderner Prozessoren getrimmt sind. Schnell und genau.
Teilweise können die das gar nicht, was wir als float kennen.

Der Wertebereich von Float ist (außer auf AVR) kleiner als von Double, darum kann der implizite Cast nur in eine Richtung führen.

Das klärt nicht alle Details, des "Warum?" ...

Hi

Wir einigen uns auf:
... wie das _t ... ein Überbleibsel aus der Vergangenheit ... Punkt

MfG

Hallo,

Danke Euch. Ich gebe mich mit "Ist eben so." diesmal zufrieden. :wink: