Was passiert in “? :”? Ich habe keine Ahnung über den Rückgabetyp
Lesezeit: 6 Minuten
BellSchnee
Ich finde ((1 ? (int)1 : (unsigned int)2) > -1) ergibt sich 1 (wahr), aber eigentlich ist es so 0 (false) in Visual Studio 2017.
Ich denke, der Wert von (1 ? (int)1 : (unsigned int)2) sollte sein (int)1Weil 1 ? stimmt, und 1 > -1 wäre wahr.
Ich kenne den Grund nicht, warum das Endergebnis dieses Ausdrucks falsch ist.
Beim Casting versuche ich gerne ((int)(1 ? (int)1 : (unsigned int)2) > -1)es kehrt zurück 1 (Stimmt).
signed int test = -1;
signed int si = 1;
unsigned int ui = 2;
printf("%d\n", ((1 ? si : ui) > test));
return 0;
Ich erwarte, dass die Ausgabe sein wird 1aber die eigentliche Ausgabe ist 0.
Die Art von (WHATEVER ? (int)1 : (double)42) ist immer gleich. Der Typ ändert sich nicht, wenn Sie ihn ändern WHATEVER. Sehen c99 6.5.15.
– pmg
6. Januar 2019 um 14:30 Uhr
Mögliches Duplikat der Vergleichsoperation für vorzeichenlose und vorzeichenbehaftete Ganzzahlen
– Manny
6. Januar 2019 um 14:36 Uhr
@manjy: Dies ist kein Duplikat davon. Diese Frage und ihre beste Antwort befassen sich mit binären Operatoren. Zuerst, ? : ist kein binärer Operator, und unabhängig vom Wert seines ersten Operanden werden die letzten beiden Operanden nicht in einer Operation kombiniert. Es ist richtig, dass die üblichen arithmetischen Umrechnungen gelten, wenn ? : hat arithmetische Operanden, aber diese Frage sagt das nicht, da es nicht um die geht ? : Operator. (Zusätzlich, ? : kann nicht arithmetische Operanden haben.)
– Eric Postpischil
6. Januar 2019 um 15:03 Uhr
Eric Postpischil
Die Art von a ? b : c ist nicht abhängig a. Sie wird bedingungslos durch die Typen bestimmt b und c. Die vollständigen Regeln sind kompliziert, aber bei arithmetischen Operanden wird der Typ durch die üblichen arithmetischen Konvertierungen bestimmt. Tatsächlich werden die beiden Operanden in einen gemeinsamen Typ konvertiert. Zum int und unsigned intder resultierende Typ ist unsigned int.
Der Bedingungsoperator, ? : ist in Abschnitt 6.5.15 des C 2018-Standards beschrieben. Absatz 4 besagt, dass das Ergebnis „in den unten beschriebenen Typ umgewandelt“ wird.
Absatz 5 beschreibt das Ergebnis für arithmetische Typen, Strukturen und Vereinigungen:
Wenn sowohl der zweite als auch der dritte Operand einen arithmetischen Typ haben, ist der Ergebnistyp, der durch die üblichen arithmetischen Konvertierungen bestimmt würde, wenn sie auf diese beiden Operanden angewendet würden, der Typ des Ergebnisses. Wenn beide Operanden den Typ Struktur oder Union haben, hat das Ergebnis diesen Typ. Wenn beide Operanden vom Typ void sind, hat das Ergebnis den Typ void.
Arithmetische Typen sind Integer- und Fließkommatypen gemäß 6.2.5 18. (Dazu gehören sowohl reelle als auch komplexe Typen.) Die üblichen arithmetischen Konvertierungen sind in 6.3.1.8 1 beschrieben, und zwar (in meiner Zusammenfassung nicht zitiert):
Wenn es sich bei einem von beiden um einen komplexen Typ handelt, ist das Ergebnis komplex, und die verbleibenden Regeln beschreiben den Typ der Real- und Imaginärteile. Andernfalls ist das Ergebnis reell und die verbleibenden Regeln beschreiben seinen Typ.
Wenn beides ist long doubleDas Ergebnis ist long double.
Andernfalls, wenn beides ist doubleDas Ergebnis ist double.
Andernfalls, wenn beides ist floatDas Ergebnis ist float.
Andernfalls werden die Integer-Promotions auf jeden Operanden angewendet (diese sind in 6.3.1.1 2 angegeben), und dann werden die beiden Typen in einen gemeinsamen Integer-Typ konvertiert. Die vollständigen Regeln dafür sind etwas kompliziert, verwenden ein erklärungsbedürftiges Rangkonzept und decken einige esoterische Situationen ab, daher fasse ich sie nur für normale Situationen zusammen: Wenn beide Arten sind int oder schmaler (d. h. weniger Bits oder die gleiche Anzahl von Bits, aber mit Vorzeichen statt ohne Vorzeichen), ist das Ergebnis int. Ansonsten, wenn beides ist unsigned int oder schmaler, das Ergebnis ist unsigned int. Andernfalls ist das Ergebnis der breitere Typ.
Die Struktur-, Union- und Void-Regeln sind klar: Die beiden Operanden müssen denselben Typ haben, und das ist das Ergebnis.
Absatz 6 beschreibt das Ergebnis für Zeiger:
Wenn sowohl der zweite als auch der dritte Operand Zeiger sind oder einer eine Nullzeigerkonstante und der andere ein Zeiger ist, ist der Ergebnistyp ein Zeiger auf einen Typ, der mit allen Typbezeichnern der Typen qualifiziert ist, auf die beide Operanden verweisen. Wenn außerdem beide Operanden Zeiger auf kompatible Typen oder auf unterschiedlich qualifizierte Versionen von kompatiblen Typen sind, ist der Ergebnistyp ein Zeiger auf eine entsprechend qualifizierte Version des zusammengesetzten Typs; wenn ein Operand eine Nullzeigerkonstante ist, hat das Ergebnis den Typ des anderen Operanden; andernfalls ist ein Operand ein Zeiger auf Leere oder eine qualifizierte Version von Leerein diesem Fall ist der Ergebnistyp ein Zeiger auf eine entsprechend qualifizierte Version von Leere.
Zusammengefasst heißt das:
Wenn einer der Operanden Qualifizierer (const, volatile, restrictoder _Atomic), schließen Sie diese in den Ergebnistyp ein.
Wenn die beiden Typen unterschiedlich, aber kompatibel sind (z. B. ein Array unbekannter Größe und ein Array bekannter Größe, beide mit demselben Elementtyp), dann kombinieren Sie die beiden Typen. (Andere Kombinationsmöglichkeiten neben der Array-Größe umfassen die Elemente der Arrays, die unterschiedliche, aber kompatible Typen sind, eine Funktion mit und ohne Parameterliste und die Parameter für Funktionen, die unterschiedliche, aber kompatible Typen sind.)
Ist es Ihrer Antwort zufolge also richtig zu verstehen, dass der Ergebnistyp meines Codes „unsigned int“ ist, weil der Satz „Wenn sowohl der zweite als auch der dritte Operand einen arithmetischen Typ haben, der Ergebnistyp, der durch die bestimmt würde Übliche arithmetische Konvertierungen, wenn sie auf diese beiden Operanden angewendet werden, ist die Art des Ergebnisses.” ?
– BellSchnee
6. Januar 2019 um 15:08 Uhr
@ BellSnow: Ja.
– Eric Postpischil
6. Januar 2019 um 15:44 Uhr
Sie sollten vorzeichenbehaftete und vorzeichenlose Werte nicht mischen, es sei denn, Sie wissen genau, was sich abspielt (und Sie wollen dieses Verhalten). [checkout here why]. Hinter den Kulissen, wie Sie haben unsigned Zahl in Ihrem Ausdruck, C wird Ihr Größer-als-Operator zu einem ausgewertet unsigned integer >. Daher wird Ihr Vergleich nicht bewertet true wie “unsigned -1„ist größer als dein unsigned 1.
OP glaubte nicht, dass sie signierte und unsignierte Werte mischten. Sie glaubten, dass sie entweder einen signierten oder einen unsignierten Wert von erhielten ? :; das wussten sie nicht ? : kombiniert die Typen.
– Eric Postpischil
6. Januar 2019 um 14:59 Uhr
In der Tat. Ich habe allgemein geschrieben.
– Delirium
6. Januar 2019 um 15:01 Uhr
Ihr Rat ist sehr vernünftig, das Mischen von vorzeichenbehafteten und vorzeichenlosen Typen in arithmetischen Ausdrücken sollte vermieden werden, da die Regeln kompliziert und etwas kontraintuitiv sind. In der Tat, mit einem unsigned Operand erzwingt möglicherweise nicht immer eine unsigned resultierender Typ: zum Beispiel ((1 ? (long)1 : (unsigned)2) > -1) kann auf verschiedenen Plattformen zu unterschiedlichen Ergebnissen führen, abhängig von der jeweiligen Größe der Typen int und long.
– chqrlie
6. Januar 2019 um 15:44 Uhr
@chqrlie genau! Dieses Verhalten ist noch schwieriger zu beheben.
– Delirium
7. Januar 2019 um 10:48 Uhr
@delirium: bug oder debug, das ist hier die frage… :)
– chqrlie
7. Januar 2019 um 13:46 Uhr
AnT steht zu Russland
Das Ergebnis Ihrer ?: Der Operator hat einen vorzeichenlosen Typ, da es sich um die handelt gemeinsames Typ für int und unsigned (Ihr 2. und 3. Operand). Das Ergebnis hat den “erwarteten” Wert von 1aber sein Typ ist unsigned.
Der Rest hat damit nichts zu tun ?: überhaupt. Es ist in zahlreichen Antworten auf diese häufig gestellte Frage gut beschrieben: Vergleichsoperation für vorzeichenlose und vorzeichenbehaftete Ganzzahlen
Nur um es zu nummerieren, wenn ich diesen Code lösche:
unsigned x = (unsigned)-1;
In ein Programm, das ich gerade debugge, hat X den Wert 4294967295 (UINT_MAX), dh Ihr Programm “sieht” den Vergleich etwa so:
((1 ? (int)1 : (unsigned int)2) > 4294967296)
(Hätte dies als Kommentar eingegeben, aber ich habe nicht den Ruf.)
12032100cookie-checkWas passiert in “? :”? Ich habe keine Ahnung über den Rückgabetypyes
Die Art von
(WHATEVER ? (int)1 : (double)42)
ist immer gleich. Der Typ ändert sich nicht, wenn Sie ihn ändernWHATEVER
. Sehen c99 6.5.15.– pmg
6. Januar 2019 um 14:30 Uhr
Mögliches Duplikat der Vergleichsoperation für vorzeichenlose und vorzeichenbehaftete Ganzzahlen
– Manny
6. Januar 2019 um 14:36 Uhr
@manjy: Dies ist kein Duplikat davon. Diese Frage und ihre beste Antwort befassen sich mit binären Operatoren. Zuerst,
? :
ist kein binärer Operator, und unabhängig vom Wert seines ersten Operanden werden die letzten beiden Operanden nicht in einer Operation kombiniert. Es ist richtig, dass die üblichen arithmetischen Umrechnungen gelten, wenn? :
hat arithmetische Operanden, aber diese Frage sagt das nicht, da es nicht um die geht? :
Operator. (Zusätzlich,? :
kann nicht arithmetische Operanden haben.)– Eric Postpischil
6. Januar 2019 um 15:03 Uhr