ProgrammingEmbedded Developer, Backend Developer

Explain the structure and operation of the conditional operator (ternary operator) in C. What pitfalls are associated with type conversion and side effects encountered when using it?

Pass interviews with Hintsage AI assistant

Answer

The ternary conditional operator (?:) allows you to evaluate and return one of two expressions based on a condition:

result = cond ? expr_true : expr_false;
  • The type of the result is determined by the usual rules of "usual arithmetic conversions" (if both expressions are numbers) or by the type of the larger operand (for pointers and structures).
  • Both expressions must be compatible in type. If they are of different types, the compiler will attempt to convert them to a common type, sometimes resulting in unexpected results or data loss.
  • The ternary operator allows side effects to occur in both expressions, but only the required one based on the condition is evaluated.
  • Complications can arise from ambiguities or unpredictable behavior with complex expressions (especially with nesting or when using macros and functions).

Example

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

Trick Question

"If the two expressions of the ternary operator return objects of different types (for example, a pointer and zero), what will be the type of the result?"

Many claim that the compiler always "guesses" the result type. In fact, if one of the expressions is a pointer and the other is 0 or NULL, the result will have the pointer type. If the types are more complex – for instance, a pointer of a different type or an int and an enum type – there can be non-obvious information loss, and sometimes the compiler will issue an error.

struct node *p = NULL; void *v = cond ? p : NULL; // ok void *z = cond ? p : 0; // ok int i = cond ? 0 : "abc"; // error: incompatible types

Examples of Real Errors Due to Ignorance of Subtleties


Story

In a large cross-compilation project, the expression cond ? ptr : 0 returned a pointer with one compiler and an int with another (where 0 was strictly interpreted as int). The system crashed when trying to use the result as a pointer.


Story

In a financial package, where return functions used the ternary operator with "bare" literals (cond ? 0.0 : 1), the result type accidentally became double, while int was expected, leading to comparison and printing errors.


Story

In one library, a call was made with an expression involving a side effect: flag ? inc(x) : dec(x). During refactoring, a hidden error occurred: both expressions called a function (with their side effects), while only one was expected to execute. Confusion with nested macros led to double modification of the value, which was discovered only during detailed testing.