1

Lets say we have the following expression:

(x>y) ? printf("type of int") : func_string()

So what do we have here?

x>y -> true -> printf("type of int") -> the type of the expression is int (because printf function is an int type function).

or

x>y -> false -> calls func_string() function which for the purpose of the question, returns a string.

The conclusion is that we have only 2 options for the outcome of this expressions: an int function (prinf) OR a string function (func_string).

Which means there are 2 possible types for the expressions.

However, the compiler can't really wait until the runtime to get the type of the expression, the compiler can't really compile the code while not being sure if the expression's type is an int or a string, so are we gonna get a compile error if we will try to run this sort of code, with 2 different types for the 2 outcomes of the conditional operator.

Lundin
  • 195,001
  • 40
  • 254
  • 396
NoobCoder
  • 513
  • 3
  • 18
  • Can't really be answered without knowing what `func_string` looks like. This might be invalid C code for all I know. – Lundin Feb 11 '21 at 15:07
  • as I said, lets just address func_string as something that returns a string type output. I don't really care whether it's a func_string or some other string. – NoobCoder Feb 11 '21 at 15:12
  • 1
    The conditionally evaluated expressions must provide values that are of compatible types. I get a warning (actually, I get an error because I use `-Werror` to convert all warnings to errors) about `pointer/integer type mismatch in conditional expression`. – Jonathan Leffler Feb 11 '21 at 15:13
  • Which means that my example won't be compile because string & int are not compatible types. But float & int would be compiled? – NoobCoder Feb 11 '21 at 15:15
  • 1
    Yes — string and int are not compatible, so you get a warning. `int` and `double` (or `float`) are compatible enough that you don't get a warning, even with extensive warnings enabled. – Jonathan Leffler Feb 11 '21 at 15:17
  • @NoobCoder I added an explanation of the float and int etc case to my answer. – Lundin Feb 11 '21 at 15:21
  • `?:` is not a replacement for an `if-else` control structure and should not be used in that manner - instead of `condition ? this-action : that-action`, it's meant to be used as `x = condition ? this-value : that-value`. – John Bode Feb 11 '21 at 15:31
  • You know, you could have made this a lot simpler with simply `x>y ? 5 : 5.0` or `x>y ? 5 : (void*)5` or something. – klutt Feb 11 '21 at 15:32
  • If you don't use the result of the whole expression, your code should be written as an explicit `if (x > y) printf(…); else func_string();` (though if the function returns a `char *`, you need to be sure it isn't a pointer to allocated memory that should be freed, and it's puzzling that the side-effects of calling `func_string()` are useful (but not impossible, and the pointer returned may not need freeing). – Jonathan Leffler Feb 11 '21 at 15:39

1 Answers1

8

The standard C17 6.5.15 specifies that the operands must behave according to this:

Constraints

The first operand shall have scalar type.

One of the following shall hold for the second and third operands:
— both operands have arithmetic type;
— both operands have the same structure or union type;
— both operands have void type;
— both operands are pointers to qualified or unqualified versions of compatible types;
— one operand is a pointer and the other is a null pointer constant; or
— one operand is a pointer to an object type and the other is a pointer to a qualified or
unqualified version of void.


In your example, (x>y) ? printf("type of int") : func_string();, printf returns type int which is an arithmetic type. func_string() supposedly returns a char*, which is a pointer type. This use case doesn't match any of the above listed valid scenarios, since the types are not compatible.

And so the compiler reports that the code isn't valid C. Some examples of compiler diagnostics:

icc:

operand types are incompatible ("int" and "char *")

gcc:

pointer/integer type mismatch in conditional expression


In case the 2nd and 3rd operands had been compatible or at least both arithmetic types (one float and one int etc), then this rule from 6.5.15 applies:

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.

To understand that part, you need to understand the meaning of the usual arithmetic conversions, see Implicit type promotion rules

The bottom line is that ?: is not some glorified if-else replacement, but a rather peculiar operator that comes with lots of special rules. ?: also has very few valid use-cases in real C code, one of the few valid uses for it is certain function-like macros.

Lundin
  • 195,001
  • 40
  • 254
  • 396