«error:« _Generic »указывает два совместимых типа», но не на некоторых компиляторах - PullRequest
2 голосов
/ 26 марта 2020

У меня есть (сложный) код, который работает на компиляторе IAR. Я принял участие в этом коде, чтобы создать фрагмент для его улучшения. Но при переносе части этого кода на онлайн-компилятор он не будет компилироваться.

«error: '_Generic' указывает два совместимых типа»

, поскольку я использовал _Generi c как этот пример:

#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_ )

С TYPE_XXX, являющимся #define, я могу вызвать

switch(GET_TYPE_(myVariable))
{ 
case TYPE_XXXX: do_something(); break;
...
}

Но когда я переместил его с помощью онлайн-компилятора (онлайн-GDB) с помощью g cc, я получил ошибку:

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, \

Я прочитал, что это нормальное поведение и что оно не должно компилироваться. Тем не менее, как это можно скомпилировать в IAR?

(да, я прошу вас поверить мне без воспроизводимого рабочего примера, потому что я не предоставлю свой пропреторный код)


Редактировать: Вкл. Годболт :

  • x86-64 clang 10,: код работает только на С ++! и в C выдает похожую ошибку:
    • "type 'someEnum1_e*' in generic association compatible with previously specified type 'uint32_t *' (aka 'unsigned int *')"
  • ARM64 G CC 8.2, флаг -std = c11: код выдает ошибку
  • x64 G CC 9.3, флаг -std = c11: код выдает ошибку
  • AVR G CC 5.4, флаг -std = c11: код не распознает _Generi c, ни _Bool:
    • "error: '_Generic' was not declared in this scope"
  • MSP430 G CC 6.2.1, флаг -std = c11: код работает! (но не в C ++)
  • и на моем компьютере с IAR 8.20.2, флаг -std = c11: код работает!

1-й бонусный вопрос : Это может быть ошибка компилятора? Что говорится в стандарте?

2-й бонусный вопрос: есть ли способ избежать ошибки? (для всех компиляторов)

Короткий фрагмент для проверки моих высказываний

#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;};
}

1 Ответ

0 голосов
/ 26 марта 2020

Я нашел способ компиляции и запуска со всем компилятором в C11 (который принимает ключевое слово _Generi c):

#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=0,
    ENUM1_B,
}someEnum1_e;


typedef union
{
    someEnum1_e value;
}someEnum1_e_t;


void print_uint32_t(uint32_t val)
{
    printf("uint32_t val = %u\n",val);
}

void print_someEnum1_e_t(someEnum1_e_t val)
{
    printf("someEnum1_e_t val = %u\n", val.value);
}

#define  PRINT_(data) _Generic((&data)+0, \
           uint32_t* : print_uint32_t((uint32_t)*((uint32_t*)&data)), \
           someEnum1_e_t* : print_someEnum1_e_t((someEnum1_e_t)*((someEnum1_e_t*)&data)), \
           default: printf("hello\n"))

int main (void)
{
    uint32_t       foo = 32;
    someEnum1_e_t  blah = {ENUM1_A};


    PRINT_(foo);
    PRINT_(blah);
}

Чтобы это решение работало, мне не нужен макрос трюк, данный Лундином.

...