mikrocontroller.net

Forum: Compiler & IDEs C++ Compiler Warnings Template Funktion


Autor: Josh S. (joooooosh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen,

wie muss eine C++ Template Funktion programmiert werden, damit der 
Compiler keine Warnings mehr auswirft?

Ich habe eine Template Funktion der eine Variable als Referenz übergeben 
wird. Diese Variable wird in der Funktion geändert.

Die Funktion sieht wiefolg aus:
  // Klassenvariablen
  uint32_t flashAddresse;
  uint8_t sektorNummer; 

  template<class T>
  int16_t getAttribute(int16_t ID, T& argpAttribute)
  {
    switch (ID) {
      case FLASHADDRESSE_ID:
        if(typeid(argpAttribute) == typeid(flashAddresse)){
          argpAttribute = flashAddresse;
        }

        break;
      case SEKTORNUMMER_ID:
        argpAttribute = sektorNummer;
        break;
      default:
        return NOPARAM_IN_FLASH;
    }
    return SUCCESS;
  }

Dabei gibt der Compiler diese Warnung:

"conversion to 'short int' from 'uint32_t {aka long unsigned int}' may 
alter its value [-Wconversion]"


bei folgender Zeile:
argpAttribute = flashAddresse;

Hat irgendjemand eine Idee wie man das programmieren kann ohne dass 
Compiler Warnungen ausgegeben werden?

Viele Grüße

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Josh S. schrieb:
> if(typeid(argpAttribute) == typeid(flashAddresse)){

Warum hier Laufzeit-Typinformationen verwenden? Besser geht's so:
if constexpr (std::is_same_v<T, decltype(flashAdresse)>) {

Josh S. schrieb:
> Hat irgendjemand eine Idee wie man das programmieren kann ohne dass
> Compiler Warnungen ausgegeben werden?

Kommt darauf an was du mit den überzähligen Bits machen möchtest... 
sektorNummer enthält 32bit, argpAttribute in deinem Fall anscheinend 
vermutlich 16. Was wenn sektorNummer = 100000 ist? Das passt 
wahrscheinlich nicht in einen short int. Wenn du sicher bist dass der 
Typbereich immer passt, einfach einen Cast einfügen:
argpAttribute = static_cast<T> (sektorNummer);

Sicher dass da nicht noch irgendwo Referenzen und Zeiger fehlen? Eine 
Adresse direkt auf einen Wert zuweisen klingt irgendwie falsch.

Autor: Josh S. (joooooosh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi Niklas G.

vielen Dank für die schnelle und ausführliche Antwort.

Mit dem Ausdruck
if constexpr (std::is_same_v<T, decltype(flashAdresse)>)

funktioniert es denk ich nicht, da die Übergabetypen nicht const. sind 
und somit zur Compilezeit nicht ausgeführt werden können?!

Habe nun folgende Lösung verwendet:
  template<class T>
  int16_t getAttribute(int16_t ID, T& argpAttribute)
  {
    switch (ID) {
      case FLASHADDRESSE_ID:
        if (typeid(argpAttribute) == typeid(flashAddresse)) {
          argpAttribute = static_cast<T> (flashAddresse);
        }else{
          return FALSCHER_TYP;
        }
        break;
      case SEKTORNUMMER_ID:
        argpAttribute = sektorNummer;
        break;
      default:
        return NOPARAM_IN_FLASH;
    }
    return SUCCESS;
  }

Hiermit ist der Compiler zufrieden.

Niklas G. schrieb:
> Sicher dass da nicht noch irgendwo Referenzen und Zeiger fehlen? Eine
> Adresse direkt auf einen Wert zuweisen klingt irgendwie falsch.

Die Addresse wird absichtlich einen Wert zugewiesen um Sektor und 
Pagebereich im Flash zu berechnen.

Viele Grüße

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Josh S. schrieb:
> funktioniert es denk ich nicht, da die Übergabetypen nicht const. sind
> und somit zur Compilezeit nicht ausgeführt werden können?!

Hä? Typen sind immer zur Kompile-Zeit fix. Das "if constexpr" und 
"is_same_v" gibt's erst ab C++17, du musst deinen Compiler also ggf. auf 
C++17 einstellen. Für ältere Sprachstandards kannst du es so machen:
if (std::is_same<T, decltype(flashAdresse)>::value)
Aber dann muss der Code im if-Block korrekt kompilierbar sein, auch wenn 
er niemals ausgeführt wird.

"typeid" würde ich auf Mikrocontrollern grundsätzlich nicht benutzen 
weil es zusätzlichen Speicher braucht.

Wäre es nicht ggf. clever die "ID" als template-Parameter zu übergeben? 
Die sollte ja sowieso zum Typ passen. Du könntest dann auch anhand der 
ID spezialisieren sodass das switch-case ganz wegfällt und auch der Typ 
kein template-Parameter mehr sein muss; dann kann man die Funktion gar 
nicht mehr falsch aufrufen.

Andererseits - warum überhaupt template-Funktionen? Warum nicht ganz 
simpel:
void getFlashAddress (uint32_t a) { flashAddresse = a; }
void getSector (uint8_t s) { sektorNummer = s; }

: Bearbeitet durch User
Autor: Josh S. (joooooosh)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
okay alles klar vielen Dank für die Infos.

Verwende nun
if (std::is_same<T, decltype(flashAdresse)>::value)

anstatt "typeid" hinsichtlich des Speichers.


Niklas G. schrieb:
> Andererseits - warum überhaupt template-Funktionen? Warum nicht ganz
> simpel:void getFlashAddress (uint32_t a) { flashAddresse = a; }
> void getSector (uint8_t s) { sektorNummer = s; }

Gute Frage^^ Wollte es halt mit einer Funktion machen.

Autor: Sven B. (scummos)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Josh S. schrieb:
> Niklas G. schrieb:
>> Andererseits - warum überhaupt template-Funktionen? Warum nicht ganz
>> simpel:void getFlashAddress (uint32_t a) { flashAddresse = a; }
>> void getSector (uint8_t s) { sektorNummer = s; }
>
> Gute Frage^^ Wollte es halt mit einer Funktion machen.

Ist aber nur aus Coolness-Gründen sinnvoll und hilft weder der 
Lesbarkeit, noch der Performance. ;)

Autor: Niklas G. (erlkoenig) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sven B. schrieb:
> Ist aber nur aus Coolness-Gründen sinnvoll und hilft weder der
> Lesbarkeit, noch der Performance. ;)

Ja, verschiedene Aspekte in eine Funktion quetschen sind nicht immer so 
sinnvoll. Insbesondere hast du jetzt eine Fehlermöglichkeit eingebaut - 
beim Aufruf könnte man eine nicht existente ID übergeben oder der Typ 
könnte nicht zur ID passen. Diese Fehler bemerkt man erst bei der 
Ausführung; wenn der entsprechende Codeteil aber nur selten ausgeführt 
wird ggf. erst sehr spät. Da ist es besser einfach nur zwei Funktionen 
zu nehmen - nicht existente Funktionen kann man nicht aufrufen, und 
falsche Typen würde der Compiler direkt bemängeln.
Verwirrend ist es für den Leser auch - er sucht den Grund, warum die 
komplexe template-Funktion nötig ist und die zwei einzelnen Funktionen 
nicht ausreichen.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.