Этот вопрос касается gcc-конструктора, компиляции & Ссылка правильная, но она НЕ запускается.GCC constructor NOT execute
Существует a.c:
UTEST_BEGIN()
UID(a_test)
{
printf("a test");
return true;
}
UTEST_END(a)
b.c является simlar:
UTEST_BEGIN()
UID(b_test)
{
printf("b test");
return true;
}
UTEST_END(b)
Объект код использует UID() ссылаются некоторые функции тестирования. Моя первая версия добавляет UTEST_BEGIN() UTEST_END(), чтобы заключить UID(), наконец, я понимаю, что UTEST_BGIN() UTEST_END() не требуется, когда я их изменяю, получается непредсказуемый результат.
Когда я изменяю определение UTEST_BEGIN(), UID(), UTEST_END(), у меня получается другой результат.
Основная идея исходит от can-i-auto-collect-a-list-of-function-by-c-macro!
Тест 1:
#define UTEST_BEGIN() \
static const bool __m_en = true; \
static struct __uti *__m_uti_head = NULL;
bool utest_item_list_add_global(struct __uti *uti);
#define UID(f) \
static bool __uti_##f(void); \
__attribute__((constructor)) \
static void uti_construct_##f(void) \
{ \
printf("%s\n", #f); \
static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f }; \
utest_item_list_add_global(&__m_uti_##f); \
} \
static bool __uti_##f(void)
bool unit_test_item_pump_do(int file_id, bool (*f)(void), const char *f_name);
#define UTEST_END(file_name) \
bool unit_test_##file_name(void) \
{ \
if (!__m_en) \
return true; \
struct __uti *cur; \
for(cur = __m_uti_head; cur; cur = cur->next) { \
unit_test_set_run_last_line(__LINE__); \
if (!unit_test_item_pump_do(this_file_id, cur->f, cur->f_name)) \
return false; \
} \
return true; \
}
Я получил правильный результат. Я могу вызвать __uti_a_test() и __uti_b_test() по ссылке. Фактически, ссылка __uti_xxx() НЕ реализована с __m_uti_head, поэтому я хочу удалить UTEST_BEGIN() & UTEST_END().
запустить GCC -E переменного тока, макро простираться:
static const bool __m_en = 1;
static struct __uti *__m_uti_head = ((void *)0);
static bool __uti_a_test(void);
__attribute__((constructor))
static void uti_construct_a_test(void)
{
static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" };
utest_item_list_add_global(&__m_uti_a_test);
}
static bool __uti_a_test(void)
{
printf("a test");
return 1;
}
bool unit_test_a(void)
{
if (!__m_en)
return 1;
struct __uti *cur;
for(cur = __m_uti_head; cur; cur = cur->next) {
unit_test_set_run_last_line(19);
if (!unit_test_item_pump_do(file_id_a, cur->f, cur->f_name))
return 0;
}
return 1;
}
Тест 2:
#define UTEST_BEGIN()
bool utest_item_list_add_global(struct __uti *uti);
#define UID(f) \
static bool __uti_##f(void); \
__attribute__((constructor)) \
static void uti_construct_##f(void) \
{ \
printf("%s\n", #f); \
static struct __uti __m_uti_##f = {NULL, this_file_id, __uti_##f, #f }; \
utest_item_list_add_global(&__m_uti_##f); \
} \
static bool __uti_##f(void)
#define UTEST_END(file_name)
Определение UID() такой же, как в испытании 1. Я держать UTEST_BEGIN() & UTEST_END() как пустое. Компиляция & Ссылка правильная, но uti_construct_a_test() & uti_construct_b_test() НЕ выполняется.
запустить НКУ -E переменного тока, макрос распространяется как:
static bool __uti_a_test(void);
__attribute__((constructor))
static void uti_construct_a_test(void)
{
static struct __uti __m_uti_a_test = {((void *)0), file_id_a, __uti_a_test, "a_test" };
utest_item_list_add_global(&__m_uti_a_test);
}
static bool __uti_a_test(void)
{
printf("a test");
return 1;
}
utest_item_list_add_global() является существование в другом .c файле, функция добавления узла в ссылку:
static struct __uti *m_uti_head = NULL;
bool utest_item_list_add_global(struct __uti *uti)
{
if (NULL == m_uti_head) {
m_uti_head = uti;
return true;
}
struct __uti *tail = m_uti_head;
while (NULL != tail->next)
tail = tail->next;
tail->next = uti;
return true;
}
Расширенное макор кажется правильным. Я думаю, проблема в стадии ссылки, я прав?
Ваш код не компилируется. Он также выглядит как рецепт для багги, неподъемного, нечитаемого кода. Не быть отрицательным;). Однако вы могли бы получить некоторое представление о том, что происходит, расширяя макросы, используя, например: 'cpp a.c> a.i'. Посмотрите на дно 'a.i'. Этот файл будет тем, что далее используется для создания кода сборки в процессе компиляции. – Runium
Использование функции GCC __attribute __ ((constructor)), поэтому любая функция, определяемая UID(), может быть связана по ссылке. И пусть пользователь просто думает и записывает тело функции тестирования, не стоит думать, что decalare & вызовет тестовые функции. Всего одна строка. Я чувствую, что это действительно здорово. – husthl
«Действительно круто» * * часто приводит к сложному содержанию кода в долгосрочной перспективе. Изобретение собственного синтаксиса (похоже, что это то, что вы делаете) еще более подвержено этому. Я думаю, @Sukminder имеет очень хороший момент. –