cgccsizeofpreprocessor-directive

_Generic length-function fails when default: sizeof(x)/sizeof((x)[0])


Issue:

Recently I learned about _Generic. In my attempt to use it as a generic length-macro I stumbled upon a weird issue. While LENA(x) works perfectly fine, the generic LEN(x) fails to compile unless I remove the default one.

#include <stdio.h>
#include <string.h>

#define LENA(x) sizeof(x)/sizeof((x)[0])
#define LEN(x) _Generic((x), \
    int                : snprintf(NULL, 0, "%d"  , (x)), \
    unsigned int       : snprintf(NULL, 0, "%u"  , (x)), \
    long               : snprintf(NULL, 0, "%ld" , (x)), \
    unsigned long      : snprintf(NULL, 0, "%lu" , (x)), \
    long long          : snprintf(NULL, 0, "%lld", (x)), \
    unsigned long long : snprintf(NULL, 0, "%llu", (x)), \
    float              : snprintf(NULL, 0, "%f"  , (x)), \
    double             : snprintf(NULL, 0, "%f"  , (x)), \
    long double        : snprintf(NULL, 0, "%Lf" , (x)), \
    default            : sizeof((x))/sizeof((x)[0]) \
)

int main() {
    int i = 12345;
    unsigned long ul = 18446744073709551615UL;
    double d = 3.14159;
    char str[] = "Hello, World!";
    int arr[] = {1, 2, 3, 4, 5, 6, 7};

    printf("Length of int  : %d\n", LEN(i));    // Output: 5
    printf("Length of Ulong: %d\n", LEN(ul));   // Output: 20
    printf("Length of array: %d\n", LENA(arr)); // Output: 7
    //printf("Length of array: %d\n", LEN(arr));
    //printf("Length of str: %d\n", LEN(str));
    return 0;
}

(specifically the /sizeof((x)[0]-part of it).

Error:

ERROR!
/tmp/21gk5WXdQu.c: In function 'main':
/tmp/21gk5WXdQu.c:15:46: error: subscripted value is neither array nor pointer nor vector
   15 |     default            : sizeof(x)/sizeof((x)[0]) \
      |                                              ^
/tmp/21gk5WXdQu.c:25:37: note: in expansion of macro 'LEN'
   25 |     printf("Length of int  : %d\n", LEN(i));    // Output: 5
      |                                     ^~~
ERROR!
/tmp/21gk5WXdQu.c:15:46: error: subscripted value is neither array nor pointer nor vector
   15 |     default            : sizeof(x)/sizeof((x)[0]) \
      |                                              ^
/tmp/21gk5WXdQu.c:26:37: note: in expansion of macro 'LEN'
   26 |     printf("Length of Ulong: %d\n", LEN(ul));   // Output: 20
      |                                     ^~~

Outro:

Is this a bug or a feature? I've searched about it, I've tried differect versions of gcc, plenty of tricks, I even asked chatGPT (but I'm not sure if it halucinates or not), so... any idea why this is happening? thanks in advance for any help.


Solution

  • _Generic selects one of the listed expressions. All of the listed items must be valid expressions. If x is not an array or pointer, x[0] is not a valid expression. _Generic is not like a preprocessor directive that can conditionally ignore some code. All of the code in it must be grammatically valid.