Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion in ternary operator and typecasting

I gone through this question -

why the result of : 1 ? (int *)0 : (void *)0
differs to the result of : 1 ? (int *)0 : (void *)1

How it is differ ? It should be 0 or (int*)0.
How to check the result ?
Where we can use such type of expression ?

like image 377
Vikram Avatar asked Dec 30 '12 19:12

Vikram


2 Answers

The only difference is in types: the first one returns an int *, the second one returns a void *.

From C11 standard, §6.5.15 Conditional operator, ¶6:

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.

(emphasis mine)

Remember that a pointer to non-void cannot be a null pointer constant but just a null pointer. C11 §6.3.2.3 Pointers, ¶3:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19.

So, here:

1 ? (int *) 0 : (void *) 0

(int *) 0 is just a null pointer while (void *) 0 is a null pointer constant, so the result has type int * ("if one operand is a null pointer constant, the result has the type of the other operand").

while here:

1 ? (int *) 0 : (void *) 1

there are no null pointer constants (only a null pointer, the first one), so the result has the composite type void * ("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").

The results have different types but they are both null pointers. Also note that the result is never 0 as you say in your question, it's always a pointer.

Unfortunately there is no standard way to see the difference in C, C++ has some support about it (typeinfo) but results are different there.

Where we can use such type of expression?

I can't think about a useful and concrete use of this obscure corner of the language.

like image 195
12 revs Avatar answered Oct 09 '22 19:10

12 revs


So effeffe already answered on why the two expressions differ:

1 ? (int *) 0 : (void *) 0  // yield (int *) 0
1 ? (int *) 0 : (void *) 1  // yield (void *) 0

To answer this question now:

How to check the result ?

With gcc you can use typeof extension and __builtin_types_compatible_p builtin function:

// The two expressions differ
printf("%d\n", __builtin_types_compatible_p(typeof(1 ? (int *) 0 : (void *) 0), typeof(1 ? (int *) 0 : (void *) 1)));

// First expression yield (int *) 0
printf("%d\n", __builtin_types_compatible_p(typeof((int *) 0), typeof( 0 ? (int *)0 : (void *)0  )));

// Second expression yield (void *) 0
printf("%d\n", __builtin_types_compatible_p(typeof((void *) 0), typeof( 1 ? (int *)0 : (void *)1  )));
like image 35
ouah Avatar answered Oct 09 '22 17:10

ouah