What is happening in “? :”? I have no idea about the return type

  • A+

I think ((1 ? (int)1 : (unsigned int)2) > -1) results in 1 (true), but actually it is 0 (false) in Visual Studio 2017.

I think the value of (1 ? (int)1 : (unsigned int)2) should be (int)1, because 1 ? is true, and 1 > -1 would be true.

I don't know the reason why the final result of this expression is false.

When I try casting like ((int)(1 ? (int)1 : (unsigned int)2) > -1), it returns 1 (true).

signed int test = -1; signed int si = 1; unsigned int ui = 2;  printf("%d/n", ((1 ? si : ui) > test)); return 0; 

I expect the output to be 1, but the actual output is 0.


The type of a ? b : c is not dependent on a. It is determined unconditionally by the types of b and c. The full rules are complicated, but, for arithmetic operands, the type is determined by the usual arithmetic conversions. In effect, the two operands are converted to a common type. For int and unsigned int, the resulting type is unsigned int.

The conditional operator, ? : is described in clause 6.5.15 of the C 2018 standard. Paragraph 4 says the result is “converted to the type described below.”

Paragraph 5 describes the result for arithmetic types, structures, and unions:

If both the second and third operands have arithmetic type, the result type that would be determined by the usual arithmetic conversions, were they applied to those two operands, is the type of the result. If both the operands have structure or union type, the result has that type. If both operands have void type, the result has void type.

Arithmetic types are integer and floating-point types, per 6.2.5 18. (These include both real and complex types.) The usual arithmetic conversions are described in 1, which are (in my summary, not quoted):

  • If either is a complex type, the result is complex, and the remaining rules describe the type of the real and imaginary parts. Otherwise, the result is real, and the remaining rules describe its type.
  • If either is long double, the result is long double.
  • Otherwise, if either is double, the result is double.
  • Otherwise, if either is float, the result is float.
  • Otherwise, the integer promotions are applied to each operand (these are specified in 2), and then the two types are converted to a common integer type. The full rules for this are somewhat complicated, use a concept of rank that requires some explanation, and cover some esoteric situations, so I will just summarize them for normal situations: If both types are int or narrower (meaning fewer bits or the same number of bits but signed instead of unsigned), the result is int. Otherwise, if both are unsigned int or narrower, the result is unsigned int. Otherwise, the result is the wider type.

The structure, union, and void rules are clear: The two operands must have the same type, and that is the result.

Paragraph 6 describes the result for pointers:

If both the second and third operands are pointers or one is a null pointer constant and the other is a pointer, the result type is a pointer to a type qualified with all the type qualifiers of the types referenced by both operands. Furthermore, if both operands are pointers to compatible types or to differently qualified versions of compatible types, the result type is a pointer to an appropriately qualified version of the composite type; if one operand is a null pointer constant, the result has the type of the other operand; otherwise, one operand is a pointer to void or a qualified version of void, in which case the result type is a pointer to an appropriately qualified version of void.

In summary, that says:

  • If either operand has qualifiers (const, volatile, restrict, or _Atomic), include those in the result type.
  • If the two types are different but compatible (such as an array of unknown size and an array of known size, both with the same type of elements), then combine the two types. (Other possibilities for combining, besides array size, include the elements of the arrays being different but compatible types, a function with and without a parameter list, and the parameters to functions being different but compatible types.)


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: