ProgrammierungEmbedded Entwickler, Backend Entwickler

Erklären Sie die Funktionsweise des Bedingungsoperators (terner Operator) in C. Welche Fallstricke sind mit Typkonversionen und Nebeneffekten verbunden, die bei seiner Verwendung auftreten?

Bestehen Sie Vorstellungsgespräche mit dem Hintsage-KI-Assistenten

Antwort

Der ternäre Bedingungsoperator (?:) ermöglicht die Auswertung und Rückgabe eines von zwei Ausdrücken, abhängig von einer Bedingung:

result = cond ? expr_true : expr_false;
  • Der Typ des Ergebnisses wird nach den allgemeinen Regeln der "üblichen arithmetischen Konversionen" bestimmt (wenn beide Ausdrücke Zahlen sind) oder nach dem Typ des größeren Operanden (für Zeiger und Strukturen).
  • Beide Ausdrücke müssen typkompatibel sein. Wenn sie unterschiedlichen Typs sind, versucht der Compiler, sie in einen gemeinsamen Typ zu konvertieren, manchmal mit unerwarteten Ergebnissen oder Datenverlust.
  • Der ternäre Operator erlaubt Nebeneffekte in beiden Ausdrücken, aber es wird nur das ausgerechnet, was je nach Bedingung erforderlich ist.
  • Bei komplexen Ausdrücken treten Probleme der Mehrdeutigkeit oder unvorhersehbares Verhalten auf (insbesondere bei Verschachtelungen oder der Verwendung mit Makros und Funktionen).

Beispiel

int a = 10, b = 0; int max = (a > b) ? a : b; // max = 10

Fangfrage

"Wenn zwei Ausdrücke des ternären Operators Objekte unterschiedlichen Typs zurückgeben (z. B. einen Zeiger und null), was wird der Typ des Ergebnisses sein?"

Viele behaupten, dass der Compiler immer den Typ des Ergebnisses "errät". Tatsächlich, wenn einer der Ausdrücke ein Zeiger ist und der andere 0 oder NULL, dann wird das Ergebnis den Typ des Zeigers haben. Wenn der Unterschied komplizierter ist – z. B. wird ein Zeiger eines anderen Typs oder der Typ int und der Typ enum zurückgegeben – kann es zu einer nicht offensichtlichen Informationsverluste kommen, oder der Compiler gibt einen Fehler aus.

struct node *p = NULL; void *v = cond ? p : NULL; // ok void *z = cond ? p : 0; // ok int i = cond ? 0 : "abc"; // Fehler: inkompatible Typen

Beispiele für echte Fehler aufgrund fehlenden Wissens über die Feinheiten des Themas


Geschichte

In einem großen Projekt mit Cross-Compilation gab der Ausdruck cond ? ptr : 0 einen Zeiger bei einem Compiler und int bei einem anderen zurück (wo 0 strikt als int interpretiert wurde). Das System stürzte ab, als versucht wurde, das Ergebnis als Zeiger zu verwenden.


Geschichte

In einem Finanzpaket, wo Rückgabefunktionen den ternären Operator mit "rohen" Literalen (cond ? 0.0 : 1) verwendeten, wurde der Typ des Ergebnisses aus Unachtsamkeit zu double, obwohl int erwartet wurde, was zu Vergleichs- und Druckfehlern führte.


Geschichte

In einer der Bibliotheken wurde ein Aufruf mit einem Ausdruck mit Nebeneffekten gemacht: flag ? inc(x) : dec(x). Bei der Umgestaltung wurde ein versteckter Fehler entdeckt: beide Ausdrücke riefen die Funktion auf (mit ihren Nebeneffekten), obwohl erwartet wurde, dass nur einer ausgeführt wird. Verwirrung durch verschachtelte Makros führte zu einer doppelten Veränderung des Wertes, was erst während ausführlicher Testungen entdeckt wurde.