这个问题是关于 gcc 构造函数的,编译和链接是正确的,但它没有运行。
有交流:
UTEST_BEGIN()
UID(a_test)
{
printf("a test");
return true;
}
UTEST_END(a)
bc 是类似的:
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 ac,宏扩展为:
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() 不执行。
运行 gcc -E ac,宏扩展为:
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;
}
扩展的宏似乎是正确的。我认为问题出在链接阶段,对吗?