Смотрим
исходники (как же там неудобно искать, проще было склонировать и найти в файлах)
Видим что этот дефайн ожидает первым аргументом X часть имени определяемых им переменными и функциями, а вторым, аргументы перед ними, т.е. в твоем примере это static (для макросов нет никакой разницы что в аргументах, лишь бы разбиралось на лексемы даже на скобки кстати пофиг)
Описание аргументов ,... это
variadic т.е. можно несколько аргументов писать в вызове макроса, они все передадутся как есть (есть разные способы их развертывания)
Вот к примеру твой пример развернется в
static vnet_feature_arc_registration_t vnet_feat_arc_ip4_unicast;
static void __vnet_add_feature_arc_registration_ip4_unicast (void)
__attribute__((__constructor__)) ;
static void __vnet_add_feature_arc_registration_ip4_unicast (void)
{
vnet_feature_main_t * fm = &feature_main;
vnet_feat_arc_ip4_unicast.next = fm->next_arc;
fm->next_arc = & vnet_feat_arc_ip4_unicast;
}
static void __vnet_rm_feature_arc_registration_ip4_unicast (void)
__attribute__((__destructor__)) ;
static void __vnet_rm_feature_arc_registration_ip4_unicast (void)
{
vnet_feature_main_t * fm = &feature_main;
vnet_feature_arc_registration_t *r = &vnet_feat_arc_ip4_unicast;
VLIB_REMOVE_FROM_LINKED_LIST (fm->next_arc, r, next);
}
static vnet_feature_arc_registration_t vnet_feat_arc_ip4_unicast
Заметь что последняя строчка не завершена, нет ";", значит если после вызова этого макроса поставить = ... то пойдет определение значения переменной vnet_feat_arc_ip4_unicast
а запись через
{ .имя_поля=значение,...}
это удобный
способ инициализировать
структуры