Перегрузка аргументов функций в C11 (в Си, не в Си++. С последним и так все понятно)
Предположим, что есть у нас функция, которая печатает на экране то число, которое в нее передали.
Назовем ее
print_number( ... )
И вот хочется нам делать такие вот вызовы:
print_number(2.0f);
print_number(-12);
print_number(655350000000);
print_number("One");
Да еще чтобы компилятор не ругался и все работало. В Си++ мы просто пишем несколько функций с названием print_number, но с разными типами аргументов.
В Си, как и в Си++ нам понадобится написать несколько функций, реализующих эту печать, но есть проблема.
В Си нам нельзя иметь одинаковые названия функций, поэтому.. Пока дадим разные.
Напишем функции печати для каждого типа аргумента, а назовем их, например
print_number_float(float arg);
print_number_integer(signed int arg);
print_number_longlong(unsigned long long arg);
А нам хотелось бы , эх, чтобы у нас была ОДНА функция печати на все, ну уж точно не с разными именами.
И тут нам на помощь приходит малозаметная фишка GCC препроцессора, _Generic. Это часть стандарта C11. С помощю дженерика мы говорим препроцессору, на что заменить нашу писанину.
Вот наши печаталки:
void print_asciiz(const char *data);
void print_unsigned(unsigned int data);
void print_signed(signed int data);
void print_float(float data);
// .. и одна специальная, на всякий случай
void __attribute__((noreturn)) print_bug(unsigned int data) { abort(); }
А вот - правила замены: на что заменить слово “print_number(…)“ в зависимости от типа этого самого “…”
// Тип аргумента : На что менять
//
#define print_number( _Item ) _Generic((_Item), \
const char * : print_asciiz, \
char * : print_asciiz, \
unsigned int : print_unsigned, \
unsigned short : print_unsigned, \
unsigned long : print_unsigned, \
unsigned char : print_unsigned, \
signed int : print_signed, \
signed short : print_signed, \
signed long : print_signed, \
signed char : print_signed, \
float : print_float, \
double : print_float, \
default : print_bug \
)( _Item)
Теперь в Си коде можно писать
print_number(2.0f);
print_number(-12);
//print_number(655350000000); <--- заленился писать
print_number("One");
И компилятор каждый раз сгенерирует вызов той функции, которую вы ему указали в _Generic. Что-то вроде switch/case но на уровне
препроцессора.
Нескучного программирования ![]()