Is there some "nice" way to check if a variable passed to a macro is a pointer? e.g.
#define IS_PTR(x) something
int a;
#if IS_PTR(a)
printf("a pointer we have\n");
#else
printf("not a pointer we have\n");
#endif
The idea is that this is not done run-time but compile-time, as in: we get different code depending on if the variable is a pointer or not. So I would like IS_PTR() to evaluate to some kind of constant expression in some way. Am I going about this idea all the wrong way?
It is certainly not observable through the preprocessor in #if
as you imply in your question. The preprocessor knows nothing about types, only tokens and expressions that are constructed from them.
C11 has a new feature that lets you observe a particular pointer type, but not "pointerness" in general. E.g you could do something
#define IS_TOTOP(X) _Generic((X), default: 0, struct toto*: 1)
or if you'd want that the macro also works for arrays
#define IS_TOTOPA(X) _Generic((X)+0, default: 0, struct toto*: 1)
There are already some compilers around that implement this, namely clang, and for gcc and others you can already emulate that feature with some builtins, see P99.
NULL is pretty much the only thing you can look for. There is no way to determine if something is a pointer.
I found a more or less _Generic
solution of this problem.
Warning: May be triggered false-positive (see an example below).
#define __INTERNAL_CHECK_POINTER(x) _Generic((x),\
int: 0, unsigned int: 0,\
long: 0, unsigned long: 0,\
long long: 0, unsigned long long: 0,\
float: 0, double: 0,\
long double: 0, \
default: 1)
/**
* Determines whether the variable has likely a pointer type (but may be triggered false-positive)
*/
#define IS_LIKELY_A_POINTER(x) ((sizeof(x) == sizeof(void*)) && __INTERNAL_CHECK_POINTER(x) ? 1 : 0)
Demo:
char c = 0;
printf("c is a pointer: %s\n", IS_LIKELY_A_POINTER(c) ? "Yes" : "No");
unsigned long long l = 0;
printf("l is a pointer: %s\n", IS_LIKELY_A_POINTER(l) ? "Yes" : "No");
double d = 0.0;
printf("d is a pointer: %s\n", IS_LIKELY_A_POINTER(d) ? "Yes" : "No");
unsigned char* cp = 0;
printf("cp is a pointer: %s\n", IS_LIKELY_A_POINTER(cp) ? "Yes" : "No");
struct tm* tp = 0;
printf("tp is a pointer: %s\n", IS_LIKELY_A_POINTER(tp) ? "Yes" : "No");
char ia[] = {0, 1, 2, 3, 4, 5, 6, 7};
printf("ia is a pointer: %s\n", IS_LIKELY_A_POINTER(ia) ? "Yes" : "No");
This will output:
c is a pointer: No
l is a pointer: No
d is a pointer: No
cp is a pointer: Yes
tp is a pointer: Yes
ia is a pointer: Yes // false-positive!
If you (like me) are looking for some logging (to draw or not to draw a *
for a particular variable) and you're not looking for fail-proof results, try this, it may help. Cheers!
NOTE that it won't compile under MSVC; use gcc/clang/etc. instead or make your own fallback implementation using this condition:
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
// use _Generic code
#else
// ¯\_(ツ)_/¯
#endif
来源:https://stackoverflow.com/questions/19255148/check-if-a-macro-argument-is-a-pointer-or-not