То, что вы хотите, выполнимо в стандартном C11, никаких расширений или G CC не требуется.
Мы доработаем до окончательного ответа, так что все могут следовать.
Согласно стандарту C11 [6.7.10], static_assert-декларация: _Static_assert( constant-expression , string-literal )
является декларацией . Таким образом, если мы собираемся использовать макрос, нам лучше всего предоставить scope для объявления, чтобы сохранить порядок. Обычно в обычной форме:
#define MY_AMAZING_MACRO() do {_Static_assert(...some magic...);} while(0)
Далее, чтобы наша _Static_assert в макросе по крайней мере повторяла через stdio фактическую проблему, если утверждение не удалось, хорошо используйте знакомую настройку строкового преобразования:
#define STATIC_ASSERT_H(x) _Static_assert(x, #x)
#define STATIC_ASSERT(x) STATIC_ASSERT_H(x)
Далее мы будем использовать функцию выбора Generi c в C11, чтобы объявить макрос, который возвращает константу 1, если объект того типа, который мы ищем, и ноль в противном случае:
#define OBJ_IS_OF_TYPE(Type, Obj) _Generic(Obj, Type: 1, default: 0)
Далее мы сделаем макрос, чтобы проверить, все ли ваши входы имеют одинаковый тип :
#define ALL_OBJS_ARE_OF_TYPE(Type, Obj_0, Obj_1, Obj_2, Obj_3) \
(OBJ_IS_OF_TYPE(Type, Obj_0) && \
OBJ_IS_OF_TYPE(Type, Obj_1) && \
OBJ_IS_OF_TYPE(Type, Obj_2) && \
OBJ_IS_OF_TYPE(Type, Obj_3))
Далее Используя вышеизложенное, сделайте макрос, чтобы проверить, все ли из ваших входов далее один из четырех типов :
#define IS_ACCEPTABLE(Type_0, Type_1, Type_2, Type_3, Obj_0, Obj_1, Obj_2, Obj_3) \
(ALL_OBJS_ARE_OF_TYPE(Type_0, Obj_0, Obj_1, Obj_2, Obj_3) || \
ALL_OBJS_ARE_OF_TYPE(Type_1, Obj_0, Obj_1, Obj_2, Obj_3) || \
ALL_OBJS_ARE_OF_TYPE(Type_2, Obj_0, Obj_1, Obj_2, Obj_3) || \
ALL_OBJS_ARE_OF_TYPE(Type_3, Obj_0, Obj_1, Obj_2, Obj_3))
И, наконец, сложив все вместе :
#define TEST_FUNC(a,b,c,d) \
do \
{ \
STATIC_ASSERT(IS_ACCEPTABLE(uint8_t, uint16_t, uint32_t, uint64_t, \
a, b, c, d)); \
} while(0)
Конечно, вы можете разделить вышеперечисленное на более отдельные, отдельные STATIC_ASSERT, как вы будете sh, если вы хотите выводить больше подробных ошибок, если какой-либо из _Static_assert
s потерпеть неудачу.