I have a (complex) code that works on IAR compiler. I took part of that code to make a snippet to improve it. But while moving a part of this code on an online compiler, it would not compile.
The "error: ‘_Generic’ specifies two compatible types"
Because I was using _Generic as this example:
#define GET_TYPE_(data) _Generic((&data)+0, \
_Bool * : TYPE_BOOL_, \
uint8_t* : TYPE_U8_, \
uint16_t* : TYPE_U16_, \
uint32_t* : TYPE_U32_, \
someEnum1_e* : TYPE_BOOL_, \
someEnum2_e* : TYPE_SPECIAL_A, \
someEnum3_e* : TYPE_SPECIAL_B, \
default: TYPE_DEFAULT_ )
With TYPE_XXX being a #define, then I can call
switch(GET_TYPE_(myVariable))
{
case TYPE_XXXX: do_something(); break;
...
}
But when I moved it with on the online compiler (online gdb) with gcc, i got the error:
error: ‘_Generic’ specifies two compatible types
someEnum1_e* : TYPE_BOOL_, \
error: ‘_Generic’ specifies two compatible types
someEnum2_e* : TYPE_SPECIAL_A, \
error: ‘_Generic’ specifies two compatible types
someEnum3_e* : TYPE_SPECIAL_B, \
I read that this was a normal behavior and that it should not compile. However, how is this possible to compile on IAR?
(yes, i'm asking you to believe me without a reproducible working example because I won't provide my propretary code)
Edit: On godbolt:
- x86-64 clang 10 ,: the code works only in c++! and in C produces a similar error:
"type 'someEnum1_e*' in generic association compatible with previously specified type 'uint32_t *' (aka 'unsigned int *')"
- ARM64 GCC 8.2, flag -std=c11: the code produces the error
- x64 GCC 9.3, flag -std=c11: the code produces the error
- AVR GCC 5.4, flag -std=c11: the code does not recognize _Generic, nor _Bool:
"error: '_Generic' was not declared in this scope"
- MSP430 GCC 6.2.1, flag -std=c11: the code works! (but not in C++)
- and on my computer with IAR 8.20.2, flag -std=c11: the code works!
1st bonus question: Could it be a compiler bug? What does the standard says?
2nd bonus question: Is there a way to avoid the error? (for all compilers)
A short snippet to test my sayings
#include <stdio.h>
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
typedef enum
{
ENUM1_A,
ENUM1_B,
}someEnum1_e;
#define TYPE_E1_ 0
#define TYPE_U32_ 1
#define GET_TYPE_(data) _Generic((&data)+0, \
uint32_t* : TYPE_U32_, \
someEnum1_e* : TYPE_E1_, \
default: TYPE_U32_ )
int main (void)
{
uint32_t foo;
someEnum1_e bar;
switch(GET_TYPE_(foo)){default:break;};
switch(GET_TYPE_(bar)){default:break;};
}