I have been following the C language hack for detecting integer constant expressions using Macros - Idea by Martin Uecker. https://lkml.org/lkml/2018/3/20/805
When I started playing around with the code, I found a weird behavior by interchanging the expressions of the ternary operator.
See the below code,
#include <stdio.h>
#include <stdlib.h>
// https://lkml.org/lkml/2018/3/20/805
#define ICE_P(x) (sizeof(int) == sizeof(*(1 ? ((void*)((x) * 0l)) : (int*)1)))
//Why is this working?
#define ICE_P2(x) (sizeof(int) == sizeof(*(1 ? (int*)1 : ((void*)((x) * 0l)))))
int main() {
int a = 5;
int b = ICE_P(a);
int c = ICE_P2(a);
int d = ICE_P(5);
int e = ICE_P2(5);
return 0;
}
ICE_P(x) works perfectly, as described in the above link. However, when I interchanged the left and right expressions of the ternary operator, the program is still behaving as the same which I was not expecting.
When ICE_P2 is called, 1 ? (int*)1 : ((void*)((x) * 0l))
will be evaluated.
Scenario with Correct behavior.
- ICE_P2(5) -
(void*)((5)*0l))
will beNULL
According to the standard, if one side of the ternary operator gets evaluated to 'NULL' then irrespective of the conditional expression the value other than NULL
will be returned.
So, in this case always, (sizeof(int) == sizeof(int*))
will be evaluated and the result will be 1
.
Scenario with the behavior I'm not understanding.
- ICE_P2(a) -
(void*)((a)*0l))
will not beNULL
My expectation:
- Now,
1 ? (int*)1 : (void*)(<Not NULL>)
should be evaluated to(int*)1
as 1 is always true. - Overall expression macro will be evaluated as
(sizeof(int) == sizeof(*(int*)))
- And the result is 1.
Actual:
- Now,
1 ? (int*)1 : (void*)(<Not NULL>)
is evaluating the value as(void*)(<Not NULL>)
. - Overall expression macro will be evaluated as
(sizeof(int) == sizeof(void*))
- And the result is 0.
For more understanding on the ICE_P
refer to the stackoverflow question or this reddit post.