Here's a solution in pure C which invokes no undefined behavior:
#define IS_INDEXABLE(arg) (sizeof(arg[0]))
#define IS_ARRAY(arg) (IS_INDEXABLE(arg) && (((void *) &arg) == ((void *) arg)))
If you need to ensure that the value is an array (then cause a compile time error if not), you can simply use it as an initializer to an enum statement (or a static variable), like this:
static int __ ## arg ## _is_array = IS_ARRAY(arg); // works for an array, fails for pointer.
I'm not entirely sure what will happen with VLA's, but playing around a bit should find that answer out rather fast.
Old answers:
Since this is tagged C (and GCC), I will attempt a solution here:
#define IS_ARRAY(arg) __builtin_choose_expr(__builtin_types_compatible_p(typeof(arg[0]) [], typeof(arg)), 1, 0)
Another solution, using C11's _Generic
feature & typeof
:
#define IS_ARRAY(arg) _Generic((arg),\
typeof(arg[0]) *: 0,\
typeof(arg[0]) [sizeof(arg) / sizeof(arg[0])]: 1\
)
Basically, all it does is use some fancy features of GCC to determine if the type of the argument is compatible with an array of the type of the argument's elements. It will return 0 or 1, and you could replace the 0 with something that creates a compile time error if you wish.