ProgrammazioneSviluppatore Embedded, Sviluppatore Backend

Spiega il funzionamento e la struttura dell'operatore condizionale (operatore ternario) in C. Quali insidie sono legate alla conversione dei tipi e agli effetti collaterali che si incontrano nel suo utilizzo?

Supera i colloqui con l'assistente IA Hintsage

Risposta

L'operatore condizionale ternario (?:) consente di calcolare e restituire una delle due espressioni a seconda della condizione:

result = cond ? expr_true : expr_false;
  • Il tipo del risultato è determinato secondo le regole generali delle "conversioni aritmetiche usuali" (se entrambe le espressioni sono numeri) oppure dal tipo dell'operando più grande (per puntatori e strutture).
  • Entrambe le espressioni devono essere compatibili per tipo. Se sono di tipo diverso, il compilatore tenterà di convertirle in un tipo comune, talvolta con risultati imprevisti o perdita di dati.
  • L'operatore ternario ammette la presenza di effetti collaterali in entrambe le espressioni, ma viene calcolato solo quello necessario secondo la condizione.
  • Nelle espressioni complesse possono sorgere problemi di ambiguità o comportamento imprevedibile (soprattutto in caso di annidamento o utilizzo con macro e funzioni).

Esempio

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

Domanda con insidia

"Se due espressioni dell'operatore ternario restituiscono oggetti di tipo diverso (ad esempio, un puntatore e zero), qual è il tipo del risultato?"

Molti sostengono che il compilatore "indovina" sempre il tipo del risultato. In realtà, se una delle espressioni è un puntatore e l'altra è 0 o NULL, il risultato avrà il tipo del puntatore. Se invece la differenza è più complessa - ad esempio, un puntatore di tipo diverso o un tipo int e un tipo enum - è possibile una perdita di informazioni non immediata, e talvolta il compilatore restituisce un errore.

struct node *p = NULL; void *v = cond ? p : NULL; // ok void *z = cond ? p : 0; // ok int i = cond ? 0 : "abc"; // errore: tipi incompatibili

Esempi di errori reali dovuti alla mancanza di conoscenza delle sottigliezze dell'argomento


Storia

In un grande progetto con cross-compilazione, l'espressione cond ? ptr : 0 restituiva un puntatore con un compilatore e int con un altro (dove 0 era interpretato rigorosamente come int). Il sistema andava in crash quando si tentava di utilizzare il risultato come puntatore.


Storia

In un pacchetto finanziario, dove le funzioni di ritorno utilizzavano l'operatore ternario con "litere" nude (cond ? 0.0 : 1), il tipo del risultato era diventato imprudentemente double, anche se ci si aspettava un int, causando errori di confronto e stampa.


Storia

In una delle librerie avveniva una chiamata con un'espressione che aveva effetti collaterali: flag ? inc(x) : dec(x). Durante il refactoring è emerso un errore nascosto: entrambe le espressioni chiamavano una funzione (con i propri effetti collaterali), mentre ci si aspettava che ne venisse eseguita solo una. La confusione con macro annidate ha portato a una doppia modifica del valore, che è stata scoperta solo durante i test dettagliati.