I want to implement IS_POINTER(P)
using _Generic
. Using this answer that implements IS_ARRAY(A)
as a starting point, I have:
#define IS_POINTER(P) \
_Generic( &(P), \
typeof(*P) ** : 1, \
default : 0 \
)
Given:
int a[1];
int *p;
int main() {
printf( "IS_POINTER(a) = %d\n", IS_POINTER(a) );
printf( "IS_POINTER(p) = %d\n", IS_POINTER(p) );
}
I get:
$ gcc -std=c2x is_pointer.c && ./a.out
IS_POINTER(a) = 0
IS_POINTER(p) = 1
which is correct. However, if I instead do:
int i;
int main() {
printf( "IS_POINTER(&i) = %d\n", IS_POINTER(&i) );
}
i.e., take the address of an object using &
to yield a pointer, I get:
is_pointer.c:5:36: error: cannot take the address of an rvalue of type 'int *'
printf( "IS_POINTER(&i) = %d\n", IS_POINTER(&i) );
^ ~~
is_pointer.c:5:13: note: expanded from macro 'IS_POINTER'
_Generic( &(P), \
^ ~
1 error generated.
I understand that you can't take the address of an rvalue, i.e., &(&i)
. My question is: is there a way to rewrite IS_POINTER()
to make it also work in cases where you explicitly take the address via &
of an object and pass that to IS_POINTER()
?
I've been kicking it around and haven't come up with a way.
You can modify your macro to make the passed argument a compound literal (which is an lvalue), to cover the &i
scenario.
#define IS_POINTER(P) \
_Generic( &(typeof(P)){0}, \
typeof(*P)** : 1, \
default : 0 \
)
However, this macro will still not work for plain variables which aren't pointers, because then typeof(*P)
is a syntax error. I'm not aware of a way to distinguish between plain variables and pointers in standard C. There are some non-standard extensions you can use: Check if a macro argument is a pointer or not