这个问题是关于gcc的构造函数,编译&链接是对的,但它不能运行。GCC构造函数不执行
有交流转换器:
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()不执行。
运行gcc -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;
}
扩大的macor似乎是正确的。我认为问题出现在链接阶段,对吗?
您的代码无法编译。它也看起来像一个越野车,不可维护,不可读的代码。不要负面;)。不过,你可能会通过使用例如'cpp a.c> a.i'来扩展宏来了解发生了什么。看看'a.i'的底部。该文件将在编译过程中进一步用于创建汇编代码。 – Runium
使用GCC __attribute __((构造函数))功能,所以任何由UID()定义的函数都可以在链接中链接。而让用户只需思考和编写测试功能体,就不用考虑测试功能。只有一条线。我觉得这很酷。 – husthl
“真的很酷”*确实会导致长期难以维护的代码。发明自己的语法(看起来就像是你在做什么)更容易这样做。我认为@Sukminder有一个很好的观点。 –