2016-11-06 10 views
1

Я хочу объявить ряд функций с одной и той же сигнатурой, возможно, разбросанных по различным заголовочным файлам, а затем использовать препроцессор для сбора в указатели массива всех таких функций, а также создать массив соответствующих имен функций.Сбор списка указателей функций и других вспомогательных данных с помощью различных макрокоманд

Так, например, если предположить общую подпись является int func(int x) я мог бы иметь следующие объявления:

FUNC(a) { 
    return x + x; 
} 

FUNC(b) { 
    return x >> 1; 
} 

FUNC(c) { 
    return x^123; 
} 

... и через какой-то макро магии, я бы конец с чем-то после предварительной обработки, которая выглядит как:

int a(int x) { 
    return x + x; 
} 

int b(int x) { 
    return x >> 1; 
} 

int c(int x) { 
    return x^123; 
} 

typedef int (*intfunc_t)(int) 

const intfunc_t func_ptrs[] = { &a, &b, &c }; 

const char *func_names[] = { "a", "b", "c" }; 

хуже вариант это возможно с помощью x-macros, но это требует такого списка:

#define X_MACRO \ 
    X(a) \ 
    X(b) \ 
    X(c) 

Это дублирует информацию, уже закодированную в определениях FUNC(a), и затрудняет использование этого подхода с неизвестным количеством функций, распространяемых по многим заголовкам, поскольку этот центральный список всегда необходимо синхронизировать.

Так что я надеюсь, что есть способ, чтобы макрос FUNC автоматически генерировал списки.

Он не имеет для сборных массивов времени, как показано, либо. Все, что позволяет мне перебирать указатели на функции и получать их имя и, возможно, другую вспомогательную информацию (добавленную через дополнительные аргументы в FUNC), может работать, например, связанный список, инициализированный при запуске. Вы можете предположить, что все макросы FUNC отображаются в одном модуле компиляции.

Хотя меня не интересуют решения, специфичные для gcc, такие как __attribute__((constructor)).

+0

Это не представляется возможным с C препроцессор. Я бы рекомендовал написать программу, которую вы запускаете во время сборки, которая сканирует ваши источники для 'FUNC (foo)' или какого-либо другого маркера и генерирует нужные вам списки. – zwol

+0

Спасибо @zwol. Я добавил пояснение внизу, что это не _have_ как массив. Это открывает возможность, например, для создания более децентрализованного подхода со связанными списками. Может ли это работать? Например, 'FUNC' расширяет функцию и линию, которая создает новый объект« Node »и добавляет себя в конец связанного списка всех существующих объектов« Node ». И тогда одна строка в начале объявляет 'head' ... – BeeOnRope

+0

, это все еще невозможно, потому что нет способа получить имя объекта _previous_' Node', чтобы связать себя. Вероятно, вы предполагали, что только одно объявление в заголовке списка нуждается в имени, но это не сработает, потому что вы не можете изменить значение уже инициализированного постоянного объекта позже в файле. – zwol

ответ

1

Это моя попытка решить вашу проблему в основном.
Это всего лишь минимальная адаптация x-макросов. Но разница может быть просто полезной для вас:

  • Фактический функциональный код остается в распределенных заголовках.
  • Список ядро ​​должно быть адаптировано к общему числу таких функций
    (и их имена, если они не одна буква алфавита),
    т.е. он не отражает функциональность только.
  • Эта адаптация к числу функций не требует редактирования основной реализации.

Вот код, все в одном "файле", с подскадками где файлы разделены.

/* content of distributed header a.h */ 
#define FUNC_a_Implementation()    \ 
{           \ 
    return x+x;        \ 
} 


/* content of distributed header b.h */ 
#define FUNC_b_Implementation()    \ 
{           \ 
    return x>>1 ;       \ 
} 


/* content of distributed header c.h */ 
#define FUNC_c_Implementation()    \ 
{           \ 
    return ParCode;       \ 
} 


/* content of core editable header */ 
/* #include here the headers a.h, b.h c.h 
    potentially d.h, e.h and f.h in the future 
*/  

#define MAGIC_LIST(ParFlavor) \ 
ENTRY_##ParFlavor(a) \ 
ENTRY_##ParFlavor(b) \ 
ENTRY_##ParFlavor(c) \ 

/* add these when needed 
ENTRY_##ParFlavor(d) \ 
ENTRY_##ParFlavor(e) \ 
ENTRY_##ParFlavor(f) \ 
*/ 


/* content of core implementation */ 
/* include editable core header */ 
#define ENTRY_Implementation(ParId) \ 
int Func##ParId (int x) \ 
FUNC_##ParId##_Implementation() 

#define ENTRY_Pointer(ParId)  \ 
&Func##ParId, 

#define ENTRY_Name(ParId)  \ 
"Func"#ParId, 

MAGIC_LIST(Implementation) 

const intfunc_t func_ptrs[] = { 
    MAGIC_LIST(Pointer) 
    NULL 
} 

const char *func_names[] = { 
    MAGIC_LIST(Name) 
    "" 
} 

При предварительной обработке этого, результат:

$MinGW\bin\gcc -E macros.c

# 1 "macros.c" 
# 1 "<built-in>" 
# 1 "<command-line>" 
# 1 "macros.c" 
# 50 "macros.c" 
int Funca (int x) { return x+x; } int Funcb (int x) { return x>>1 ; } int Funcc (int x) { return x^123; } 

const intfunc_t func_ptrs[] = { 
&Funca, &Funcb, &Funcc, 
NULL 
} 

const char *func_names[] = { 
"Func""a", "Func""b", "Func""c", 
"" 
} 

Я добавил последняя запись в массивах, чтобы избежать их intialisation оканчивающиеся на "". Но я думаю, что большинство компиляторов действительно это разрешит.
Я ожидаю, что компиляторы заменят "Func""a" на "Funca". Мне не нравятся короткие идентификаторы. Если ваш компилятор не работает должным образом, удалите «Func» всюду и потребуйте, чтобы идентификаторы были достаточно длинными.

Расширенной макросы никогда не будет иметь довольно отступы ...

0

Я бы заголовок с функцией ЬурейеЕ и прототипы:

//the_header.h 
typedef int intfunc_t(int); /*function not function pointer*/ 
intfunc_t a,b,c; /*prototypes*/ 

включить его в каждом файле реализации, а затем один файл с:

#include "the_header.h" 
const intfunc_t *func_ptrs[] = { a,b,c }; 
const char *func_names[] = { "a","b","c" }; 

Хотя можно удалить а, б, в дублирования и что-то вроде:

//the_header.h 
typedef int intfunc_t(int); /*function not function pointer*/ 
#define FUNC a,b,c 
intfunc_t FUNCS; /*prototypes*/ 


//collector.c 
#include "the_header.h" 
const intfunc_t *func_ptrs[] = { FUNCS }; 
const char *func_names[] = { STRINGIFY_EACH(FUNCS) }; 

Реализация STRINGIFY_EACH требует какую-то темную магию макросъемки (AFAIK), такие как:

#define STRINGIFY_EACH(...) MC_foreachc(MC_str, __VA_ARGS__) 


#define MC_str(_d) MC_str_impl_(_d)               
#define MC_str_impl_(s) #s              
#define MC_foreachc(What, ...) MC_foreachc_(MC_argc(__VA_ARGS__), What, __VA_ARGS__) 
    /* MC_foreachc(foo, a,b,c) foo(a), foo(b), foo(c); */ 

#define MC_foreachc_0(What, x, ...) 
#define MC_foreachc_1(What, x, ...) What(x) 
#define MC_foreachc_2(What, x, ...) What(x) , MC_expand(MC_foreachc_1(What, __VA_ARGS__)) 
#define MC_foreachc_3(What, x, ...) What(x) , MC_expand(MC_foreachc_2(What, __VA_ARGS__)) 
#define MC_foreachc_4(What, x, ...) What(x) , MC_expand(MC_foreachc_3(What, __VA_ARGS__)) 
#define MC_foreachc_5(What, x, ...) What(x) , MC_expand(MC_foreachc_4(What, __VA_ARGS__)) 
#define MC_foreachc_6(What, x, ...) What(x) , MC_expand(MC_foreachc_5(What, __VA_ARGS__)) 
#define MC_foreachc_7(What, x, ...) What(x) , MC_expand(MC_foreachc_6(What, __VA_ARGS__)) 
#define MC_foreachc_8(What, x, ...) What(x) , MC_expand(MC_foreachc_7(What, __VA_ARGS__)) 
#define MC_foreachc_9(What, x, ...) What(x) , MC_expand(MC_foreachc_8(What, __VA_ARGS__)) 
#define MC_foreachc_10(What, x, ...) What(x) , MC_expand(MC_foreachc_9(What, __VA_ARGS__)) 
#define MC_foreachc_11(What, x, ...) What(x) , MC_expand(MC_foreachc_10(What, __VA_ARGS__)) 
#define MC_foreachc_12(What, x, ...) What(x) , MC_expand(MC_foreachc_11(What, __VA_ARGS__)) 
#define MC_foreachc_13(What, x, ...) What(x) , MC_expand(MC_foreachc_12(What, __VA_ARGS__)) 
#define MC_foreachc_14(What, x, ...) What(x) , MC_expand(MC_foreachc_13(What, __VA_ARGS__)) 
#define MC_foreachc_15(What, x, ...) What(x) , MC_expand(MC_foreachc_14(What, __VA_ARGS__)) 
#define MC_foreachc_16(What, x, ...) What(x) , MC_expand(MC_foreachc_15(What, __VA_ARGS__)) 
#define MC_foreachc_17(What, x, ...) What(x) , MC_expand(MC_foreachc_16(What, __VA_ARGS__)) 
#define MC_foreachc_18(What, x, ...) What(x) , MC_expand(MC_foreachc_17(What, __VA_ARGS__)) 
#define MC_foreachc_19(What, x, ...) What(x) , MC_expand(MC_foreachc_18(What, __VA_ARGS__)) 
#define MC_foreachc_20(What, x, ...) What(x) , MC_expand(MC_foreachc_19(What, __VA_ARGS__)) 
#define MC_foreachc_21(What, x, ...) What(x) , MC_expand(MC_foreachc_20(What, __VA_ARGS__)) 
#define MC_foreachc_22(What, x, ...) What(x) , MC_expand(MC_foreachc_21(What, __VA_ARGS__)) 
#define MC_foreachc_23(What, x, ...) What(x) , MC_expand(MC_foreachc_22(What, __VA_ARGS__)) 
#define MC_foreachc_24(What, x, ...) What(x) , MC_expand(MC_foreachc_23(What, __VA_ARGS__)) 
#define MC_foreachc_25(What, x, ...) What(x) , MC_expand(MC_foreachc_24(What, __VA_ARGS__)) 
#define MC_foreachc_26(What, x, ...) What(x) , MC_expand(MC_foreachc_25(What, __VA_ARGS__)) 
#define MC_foreachc_27(What, x, ...) What(x) , MC_expand(MC_foreachc_26(What, __VA_ARGS__)) 
#define MC_foreachc_28(What, x, ...) What(x) , MC_expand(MC_foreachc_27(What, __VA_ARGS__)) 
#define MC_foreachc_29(What, x, ...) What(x) , MC_expand(MC_foreachc_28(What, __VA_ARGS__)) 
#define MC_foreachc_30(What, x, ...) What(x) , MC_expand(MC_foreachc_29(What, __VA_ARGS__)) 
#define MC_foreachc_31(What, x, ...) What(x) , MC_expand(MC_foreachc_30(What, __VA_ARGS__)) 
#define MC_foreachc_32(What, x, ...) What(x) , MC_expand(MC_foreachc_31(What, __VA_ARGS__)) 

#define MC_foreachc_(N, What, ...) MC_expand(MC_cat(MC_foreachc_, N)(What, __VA_ARGS__)) 

 Смежные вопросы

  • Нет связанных вопросов^_^