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.