這個問題是關於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有一個很好的觀點。 –