I was trying to write a macro to detect whether a struct member is a flexible array or just a regular one.
Turns out clang treats flexible array types as incomplete (yet-to-be-sized) array types.
Incomplete array types can be detected by being, on different compatibility test, compatible with different specific sizes:
#define ISCOMPWITHARRAYOFN(LVAL,N) _Generic((typeof((LVAL)[0])(*)[N])0, default:0,typeof(&(LVAL)):1)
#define ISINCOMPLETE_ARRAY(LVAL) ( ISCOMPWITHARRAYOFN(LVAL,1) && ISCOMPWITHARRAYOFN(LVAL,2) )
extern char incomplete[];
extern char complete[1];
//accepted by both gcc and clang
_Static_assert(ISINCOMPLETE_ARRAY(incomplete),"");
_Static_assert(!ISINCOMPLETE_ARRAY(complete),"");
This means that on clang, I can have:
#define ISFLEXIBLE(type,member) ISINCOMPLETE_ARRAY((type){0}.member)
struct flexed{ int a; char m[]; };
struct unflexed0{ int a; char m[1]; };
struct unflexed1{ int a; char m[1]; int b; };
//both GCC and clang accept these:
_Static_assert(!ISFLEXIBLE(struct unflexed0,m),"");
_Static_assert(!ISFLEXIBLE(struct unflexed1,m),"");
//only clang accepts these
_Static_assert(ISFLEXIBLE(struct flexed,m),"");
_Static_assert(ISCOMPWITHARRAYOFN((struct flexed){0}.m,1),"");
_Static_assert(ISCOMPWITHARRAYOFN((struct flexed){0}.m,2),"");
but GCC does not accept this.
My question is which of gcc/clang behaves incorrectly here and is it possible to write
a (perhaps nonstandard) ISFLEXIBLE(type,array_typed_member)
macro that works on both compilers?