Можно определить макрос общего типа, который поддерживает все стандартные (беззнаковые) целочисленные типы, а также size_t
?
Да - с вложенностью.
size_t
обычно соответствует стандартному целочисленному типу, например unsigned, unsigned long, unsigned long long
, но это не требуется для C. Уловка заключается в том, как использовать _Generic
, когда size_t
такой же как стандартный тип и когда это не стандартный тип.Аналогичная проблема относится к uintmax_t
.
void foo_size_t(_Bool x) { (void)x; puts("size_t"); }
void foo_bool(_Bool x) { (void)x; puts("bool"); }
void foo_uchar(unsigned char x){ (void)x; puts("unsigned char"); }
void foo_ushort(unsigned short x){ (void)x; puts("unsigned short"); }
void foo_uint(unsigned x) { (void)x; puts("unsigned"); }
void foo_ulong(unsigned long x){ (void)x; puts("unsigned long"); }
void foo_ullong(unsigned long long x){ (void)x; puts("unsigned long long"); }
void foo_none(){ puts("TBD"); }
#define foo(x) _Generic((x), \
_Bool: foo_bool, \
unsigned char: foo_uchar, \
unsigned short: foo_ushort, \
unsigned: foo_uint, \
unsigned long: foo_ulong, \
unsigned long long: foo_ullong, \
default: foo_none)(x)
// Catch `size_t` as `size_t`
// If `size_t` is distinctive, apply the size_t function
// If `size_t` is not distinctive, others will be caught here too
#define bar(x) _Generic((x), \
size_t: foo_size_t(x), \
default: foo(x) \
)
int main(void) {
foo((float)1); // What happens when type matching nothing
foo(1lu);
foo((size_t)1);
bar((float)1); // What happens when type matching nothing
bar((size_t)1);
bar(1lu);
}
Вывод
TBD
unsigned long
unsigned long // Overlap when size_t matches a type, else TBD
TBD
size_t // expect this as unsigned long if size_t was distinctive.
size_t
Обратите внимание, что creative использование _Generic
может привести к проблемам, так как это расширение дляC все еще зарождается.