It looks like the typeof operator is likely to be accepted into the next C standard, and I was looking to see if there was a way to leverage this to create a macro using portable ISO-C that can get the length of an array passed into it or fail to compile if a pointer is passed into it. Normally generic selection can be used to force a compiler error when using an unwanted type by leaving it out of the generic association list, but in this case, we need a default association to deal with arrays of any length, so instead I am trying to force a compiler error for the generic association for the type we don't want. Here's an example of what the macro could look like:
#define ARRAY_SIZE(X) _Generic(&(X), \
typeof(&X[0]) *: sizeof(struct{_Static_assert(0, "Trying to get the array length of a pointer"); int _a;}), \
default: (sizeof(X) / sizeof(X[0])) \
)
The problem is that _Static_assert is tripping even when the generic association selected is the default association. For sake of simplicity, since the issue at hand is not related anything being introduced in C23, we'll make a test program that works explicitly to reject a pointer to int:
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(X) _Generic(&(X), \
int **: sizeof(struct{_Static_assert(0, "Trying to get the array length of a pointer"); int _a;}), \
default: (sizeof(X) / sizeof(X[0])) \
)
int main(void) {
int x[100] = {0};
int *y = x;
int (*z)[100] = {&x};
printf("length of x: %zu\n", ARRAY_SIZE(x));
printf("length of y: %zu\n", ARRAY_SIZE(y));
printf("length of z: %zu\n", ARRAY_SIZE(z));
printf("length of *z: %zu\n", ARRAY_SIZE(*z));
return EXIT_SUCCESS;
}
Building the above with -std=c11, I find _Static_assert tripping on all expansions of ARRAY_SIZE when I would expect to only have problems with the pointers that will use the int ** generic association.
According to 6.5.1.1 p3 of the C11 standard for Generic Selection,
None of the expressions from any other generic association of the generic selection is evaluated
Is this a bug in gcc and clang, or is there something I've missed in the standard that would cause the compile-time evaluation of this _Static_assert in the unused generic association?