Zuweisung gemischter Variablentypen (warum keine Warning)?



  • Hi, ich zweifel gerade an meinem Verstand.
    Warum zum Henker gibt der folgende Code keine Warnungen geschweige denn Fehler?
    Das ist doch nicht etwa wirklich valider Code?
    Beim bool könnte ich mir noch vorstellen,
    dass der Wert implizit in false bzw. true umgewandelt wird.
    Hätte aber erwartet dass man hier explizit casten muss.
    Aber bei den vInt16 Zuweisungen sollten doch Warnungen kommen,
    da die meisten Werte den Gültigkeitsbereich des int16_t Typ überschreiten?
    Auch die beiden self assignments erzeugen keine Warnung.
    Was ist da los?

    #include <iostream>
    #include <limits>
    
    using namespace std;
    
    int main() {
    	bool vBool = std::numeric_limits<bool>::max();
    	unsigned char vByte = std::numeric_limits<unsigned char>::max();
    	char16_t vChar = std::numeric_limits<char16_t>::max();
    	double vDouble = std::numeric_limits<double>::max();
    	int16_t vInt16 = std::numeric_limits<int16_t>::max();
    	int32_t vInt32 = std::numeric_limits<int32_t>::max();
    	int64_t vInt64 = std::numeric_limits<int64_t>::max();
    	signed char vSByte = std::numeric_limits<signed char>::max();
    	float vSingle = std::numeric_limits<float>::max();
    	uint16_t vUInt16 = std::numeric_limits<uint16_t>::max();
    	uint32_t vUInt32 = std::numeric_limits<uint32_t>::max();
    	uint64_t vUInt64 = std::numeric_limits<uint64_t>::max();
    	
    	
            vBool = vBool;
            vBool = vByte;
    	vBool = vChar;
    	vBool = vDouble;
    	vBool = vInt16;
    	vBool = vInt32;
    	vBool = vInt64;
    	vBool = vSByte;
    	vBool = vSingle;
    	vBool = vUInt16;
    	vBool = vUInt32;
    	vBool = vUInt64;
    	
    	vInt16 = vByte;
    	vInt16 = vChar;
    	vInt16 = vDouble;
    	vInt16 = vInt16;
    	vInt16 = vInt32;
    	vInt16 = vInt64;
    	vInt16 = vSByte;
    	vInt16 = vSingle;
    	vInt16 = vUInt16;
    	vInt16 = vUInt32;
    	vInt16 = vUInt64;
    	
    	return 0;
    }
    


  • Und du hast ausdrücklich Warnungen von deinem Compiler verlangt?



  • Scheint so ein GCC-Ding zu sein. Selbst mit -Wall -Wextra. Clang und MSVC (mit -W3) geben durchaus Warnungen aus.
    Auch interessant ist Initialisierung: uint16_t x{ vUInt64 }; gibt eine Warnung mit GCC, uint16_t x = vUInt64; (eigentlich äquivanent?) jedoch nicht.

    @Enumerator Und ja, der Code ist durchaus valide, diese Integer-Konvertierungen sind klar definiert: Der resultierende Wert der Zielvariablen muss gleich dem Wert der Ausgangsvariablen modulo 2n2^n sein, wobei nn die Anzahl der Bits der Zielvariablen ist.



  • Das fällt allgemein unter das Stichwort implicit type conversion.

    Die gezeigten Zuweisungen fallen unter direct initialization, daher sind es auch keine Fehler (und Warnungen liegen im Ermessen der Compiler-Hersteller).
    Explizit ist

    otherwise, if the destination type is a (possibly cv-qualified) aggregate class, it is initialized as described in aggregate initialization except that narrowing conversions are permitted

    noch erwähnenswert, welches wohl deshalb beim GCC zu einer Warnung bei uint16_t x{ vUInt64 }; führt, weil es während es dagegen [Edited] bei der aggregate initialization eben nicht erlaubt ist, ein "Narrowing" durchzuführen.



  • @Th69 sagte in Zuweisung gemischter Variablentypen (warum keine Warning)?:

    noch erwähnenswert, welches wohl deshalb beim GCC zu einer Warnung bei uint16_t x{ vUInt64 }; führt, weil es bei der aggregate initialization eben nicht erlaubt ist, ein "Narrowing" durchzuführen.

    Ja, bei GCC greift die Warnung wohl nur bei dem (Compiler-) Codepfad mit den gewschweiften Klammern - wer weiss, vermutlich steht die Information für die Diagnosemeldung nur dort zu Verfügung, weil es eben für die Aggregate Initialization benötigt wird. Allerdings möchte ich noch hervorheben, dass es sich bei uint16_t x{ vUInt64 }; nicht um Aggregate Initialization handelt, sondern hier greifen die Standard-Konvertierungen. Das sagt wohl eher etwas darüber aus, wie GCC intern arbeitet.



  • Das habe ich auch nicht geschrieben (bzw. gemeint). 😉

    uint16_t x{ vUInt64 }; ist eine "direct initialization", aber weil es dieselbe Syntax wie eine "aggregate initialization" benutzt (und dort eben kein "Narrowing" erlaubt ist), wird wohl deshalb hierbei eine Warnung ausgegeben (während bei einer Zuweisung mittels = nur die "normale" Typkonvertierung durchgeführt wird).
    Wahrscheinlich beim GCC intern wirklich zwei verschiedene Programmzweige.



  • @Th69 sagte in Zuweisung gemischter Variablentypen (warum keine Warning)?:

    Das habe ich auch nicht geschrieben (bzw. gemeint). 😉

    Davon bin ich ausgegangen, fand es beim Lesen aber etwas missverständlich. Daher stehts auch eher beiläufig am Ende 😉



  • @Finnegan sagte in Zuweisung gemischter Variablentypen (warum keine Warning)?:

    bei GCC greift die Warnung wohl nur bei dem (Compiler-) Codepfad mit den gewschweiften Klammern - wer weiss, vermutlich steht die Information für die Diagnosemeldung nur dort zu Verfügung

    Ich glaube eher dass es daran liegt dass es viel weniger bestehenden Code gibt der Uniform-Initialization mit fragwürdiger Konvertierung verwendet als Code der die klassische Schreibweise mit fragwürdiger Konvertierung verwendet. Weiters sind bei Uniform-Initialization auch viele Dinge explizit verboten die bei der klassischen Schreibweise OK sind. z.B.

    unsigned char c = -1; // OK
    unsigned char c2 { -1 }; // Error
    

Log in to reply